如何确定当前可用的 JVM 堆大小?

问题描述 投票:0回答:1

我有一个管理/缓存大型数据对象的系统。我想确保当它加载下一个对象时,有足够的内存空间。

我可能会误解以下概念,但这就是我挣扎的地方:

  1. 我无法使用
    java.lang.Runtime.getRuntime().freeMemory()
    ,因为它不计算可以释放的内存,也就是说这个值有时会比我可能使用的内存量小得多。
  2. 我对
    maxMemory()
    totalMemory()
    的理解是它们通常比我可以分配的要大,因为它们计算程序已经占用的内存。另外,后者与 JVM 发行版无关,这在我的环境中是不可接受的。
  3. 理论上,我可以强制使用
    gc()
    ,然后使用
    freeMemory()
    获得更准确的值,但这会占用太多 CPU 时间并使服务器过载。此外,这种方法被认为是一种不好的做法。

如有错误请指出。我觉得当您有一系列大型对象要缓存在不同的池/级别等中时,这是一个相当常见的场景。我想知道是否有一个通用的解决方案或现有的库可以做到这一点。

java caching jvm heap-memory large-data
1个回答
0
投票

我想你可以手动跟踪可用内存:如果你知道如何估计缓存条目的大小,并且可以确保它在失效后可用于垃圾回收,因为你控制客户端代码,你可以使用一个简单的计数器 -可用字节数。

请参阅下面的伪代码片段作为示例。显然,代码片段中内存泄漏的可能性很大,您必须考虑并发访问等;它只是说明了这个想法。

class MemoryReservingCache<K, V> {
    // Total memory available for all caches. The initial value can be 
    // calculated based on the heap size.
    static long freeSizeBytes;

    Map<K,V> storage;
    
    // Ideally, the client code should call reserve before
    // allocating objects.
    boolean reserve(long bytes) {
        if (freeSizeBytes < bytes) {
            return false;
        }
        else {
            freeSizeBytes -= bytes;
            return true;
        }
    }

    void put(K key, V value) {
        storage.put(key, value);
    }

    V get(K key) {
        return storage.get(key);
    }

    void invalidate(K key) {
        // If there is an automatic eviction process, you may try to
        // notify the client code to synchronously make entries that 
        // being evicted available for garbage collection.
        storage.remove(key);
    }
    
    void free(long bytes) {
        freeSizeBytes += bytes;
    }
}

// Estimate the size of the (key, value) pair.
// For example, read it from some metadata.
long requiredBytes = ...;
if (!cache.reserve(requiredBytes)) {
    // Out of memory.
}

K key = ...;
V value = ...;
cache.put(key, value);

// Clear *all* references to both value and key to make sure that
// they are *available* for garbage collection if memory is needed
// for other objects.
value = null;
cache.invalidate(key);
key = null;
// Although the requiredBytes may still be unavailable according to
// System.freeMemory() they *are* available sort of on demand. 
cache.free(requiredBytes)
© www.soinside.com 2019 - 2024. All rights reserved.