我有一个Tomcat webapp,它代表客户端执行一些漂亮的内存和CPU密集型任务.这是正常的,是所需的功能.但是,当我运行Tomcat时,内存使用量会随着时间的推移而猛增至4.0GB以上,此时我通常会杀死该进程,因为它会破坏我在开发计算机上运行的所有其他内容:

我以为我无意中用我的代码引入了内存泄漏,但在用VisualVM检查后,我看到了一个不同的故事:

VisualVM将堆显示为占用大约一GB的RAM,这就是我设置它所做的事情CATALINA_OPTS="-Xms256m -Xmx1024".
根据VisualVM的说法,为什么我的系统认为这个过程占用了大量的内存,它几乎没有占用任何内容?
经过一番进一步的嗅探,我注意到如果在应用程序中同时运行多个作业,则内存不会被释放.但是,如果我等待每个作业完成,然后再向我BlockingQueue提供服务ExecutorService,那么内存将被有效回收.我该怎么调试呢?为什么垃圾收集/内存重用会有所不同?
小智 10
您无法控制要控制的内容,-Xmx只控制Java堆,它不控制JVM 对本机内存的消耗,而JVM根据实现完全不同地使用.VisualVM只显示Heap正在消耗的内容,它不会显示整个JVM作为本机内存消耗的操作系统进程.您将不得不使用操作系统级工具来查看它,并且它们将报告完全不同的数字,通常比VisualVM报告的任何数字都大得多,因为JVM 以完全不同的方式使用本机内存.
从以下文章感谢内存(了解JVM如何在Windows和Linux上使用本机内存)
维护堆和垃圾收集器使用您无法控制的本机内存.
需要更多的本机内存来维护维护Java堆的内存管理系统的状态.必须分配数据结构以跟踪免费存储并记录收集垃圾时的进度.这些数据结构的确切大小和性质随实现而变化,但许多数据结构与堆的大小成正比.
和JIT编译器使用本机内存一样javac会
字节码编译使用本机内存(与gcc等静态编译器需要运行内存的方式相同),但JIT的输入(字节码)和输出(可执行代码)也必须存储在本机内存中.包含许多JIT编译方法的Java应用程序比较小的应用程序使用更多的本机内存.
然后你有使用本机内存的类加载器
Java应用程序由定义对象结构和方法逻辑的类组成.它们还使用Java运行时类库(例如java.lang.String)中的类,并且可以使用第三方库.只要它们被使用,这些类就需要存储在内存中.如何存储类因实现而异.
我甚至不会开始引用关于Threads的部分,我认为你得到的想法是
-Xmx不控制你认为它控制的东西,它控制JVM堆,而不是JVM堆中的所有内容,并且堆占用更多本机记忆,指定用于管理和簿记的内容.
简单明了JVM使用比在供给更多的存储器-Xms和-Xmx与其他命令行参数.
这是一篇关于JVM如何分配和管理内存的非常详细的文章,它并不像你在你的问题中根据你的假设所期望的那样简单,值得全面阅读.
许多实现中的ThreadStack大小具有最小限制,这些限制因操作系统和JVM版本而异; 如果将限制设置为低于JVM或OS的本机操作系统限制,则忽略threadstack设置(有时必须设置ulix on*nix).其他命令行选项以相同的方式工作,当提供的值太小时,默认默认为更高的值.不要假设传入的所有值都代表实际使用的值.
类加载器和Tomcat有不止一个,占用了大量内存,而这些内存很难被记录下来.JIT占用了大量的内存,随着时间的推移交易空间,这在大多数情况下是一个很好的交易.
| 归档时间: |
|
| 查看次数: |
5812 次 |
| 最近记录: |