Runtime.totalMemory 显示当前可用内存。 Java 是惰性分配内存的。
另外,运行时是否会将未使用的内存(Runtime.freeMemory())返还给操作系统以供其他进程使用?
不会。如果 Java 分配了内存(totalMemory),那么它现在就在 java 进程中。
RSS:20.0g
14.3G
正如已经提到的,Java 除了堆之外还使用内存。
Gemfire 还使用堆外内存(检查这个)。
尝试在 VisualVM-Buffer Monitor 中查看它们。
您的基础设施(操作系统、虚拟机)是什么?
如果您无法使用标准工具,您可能应该使用 JMX 编写自己的可服务性代理(例如)
UPDATE
根据文档,默认情况下 Gemfire 使用 JVM 堆。
Ok
为什么对于仅使用约 10G 堆内存的进程,RSS 始终显示 20G。
如果您仍然询问,我会提供更多详细信息。 java内存使用情况是什么?
- 堆内存(Xmx);
- 堆栈内存(每个线程都有自己的堆栈线程堆栈大小, VM线程堆栈大小);
- MaxPermSize 或 MaxMetaspaceSize (最大永久代大小, 最大元空间大小);
- 直接字节缓冲区(最大直接内存大小);
- 内存池(Par Eden 空间、Par Survivor 空间、CMS Old Gen、Metaspace/PermGen、代码缓存、压缩类空间(压缩类空间大小));
- 字符串表(所有 String.intern() 都将在其中,字符串表大小);
-
性能数据内存大小;
-
标记堆栈大小;
-
编译器线程堆栈大小;
- 常量池;
- 我可能错过了某物;
要查看默认值,您可以运行:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version
要查看适合您的特定进程的选项,您可以运行:
jps -lvm
unix中是否有命令行工具来确定其余用法?
对于其中一些人来说是的。对于其中一些人来说没有。
对于直接内存,您可以尝试 sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getMemoryUsed()。
以cmd为例:
jcmd <pid> VM.native_memory baseline
但这取决于运行设置(本机内存跟踪)。您可以阅读如何启用本机内存跟踪here.
在Linux中你还可以使用:
pmap -x <pid>
总之,这可能无关紧要,因为您的任务:
请注意,我的应用程序正在使用共享和复制缓存设置的对等 GemFire 缓存系统中运行。我需要优化应用程序以减少内存占用。
并且您不能影响本机内存使用。我想看看jmaputil,它可以显示类直方图。您应该检查 GemFire 中大小较大的对象并检查这些对象,可能您存储在缓存数据中,但这些对象不应该存在。我的意思是,在优化缓存的实践中,我会检查对象和字段,看看哪些字段真正频繁,哪些字段不频繁。另一种方法是检查序列化机制和对象布局。
正如我提到的,您可以使用可服务性代理:
import com.sun.tools.attach.VirtualMachine;
import sun.tools.attach.HotSpotVirtualMachine;
import java.io.InputStream;
public class JMemoryMain {
public static void main(String[] args) throws Exception {
final int pid = JMemoryMainUtils.getPid(args);
final HotSpotVirtualMachine vm = (HotSpotVirtualMachine) VirtualMachine.attach(String.valueOf(pid));
final byte[] buffer = new byte[1024];
try (InputStream is = vm.heapHisto()) {
for (int read; (read = is.read(buffer)) > 0;) {
System.out.write(buffer, 0, read);
}
}
vm.detach();
}
}
您需要 JDK 中的依赖项中的 tools.jar 来运行它。它也可以打印类直方图,但有时可以工作,而 jmap 则不能。
另外,当您需要等待很长时间时,在计算直方图时,您可以使用 VM.getSystemDictionary() 并仅查找您的类。
而且,如果由于开销而无法启用 NMT,这将很有用。