Java 线程消耗的内存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25033458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Memory consumed by a thread
提问by Sarveswaran Meenakshi Sundaram
I need to monitor the amount of memory consumed by threads spawned by my application. The idea is to take corrective actions, if a greedy thread consumes too much of memory. I have referred to How much memory does my java thread take?. One of the suggestions on that link is to use getThreadAllocatedBytes
in ThreadMXBean.
I experimented with getThreadAllocatedBytes
with the following job.
我需要监视由我的应用程序产生的线程消耗的内存量。这个想法是在贪婪的线程消耗太多内存时采取纠正措施。我已经提到了我的 java 线程需要多少内存?. 该链接上的建议之一是getThreadAllocatedBytes
在ThreadMXBean.
我尝试getThreadAllocatedBytes
过以下工作时使用。
List<Long> primes = new ArrayList<Long>();
long i = 0;
while (true) {
primes.add(++i);
if ((i % 10) == 0) {
primes.clear();
System.runFinalization();
System.gc();
}
}
I run this job on four threads for considerable time. Though the job does not accumulate memory continuously, the values returned by getThreadAllocatedBytes
keeps increasing and does not go down even once. This implies that getThreadAllocatedBytes
does not return the actual amount of memory on heap used by the thread. It returns the total amount of memory allocated on the heap for the thread since it was started. My platform details are as follows:
我在四个线程上运行了相当长的时间。虽然job不会连续积累内存,但是返回的值getThreadAllocatedBytes
一直在增加,一次也不会减少。这意味着getThreadAllocatedBytes
不会返回线程使用的堆上的实际内存量。它返回自线程启动以来在堆上为线程分配的内存总量。我的平台详情如下:
Linux PG85213.egi.ericsson.com 3.5.0-030500-generic #201207211835 SMP Sat Jul 21 22:35:55 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
Linux PG85213.egi.ericsson.com 3.5.0-030500-generic #201207211835 SMP 周六 7 月 21 日 22:35:55 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux. Java 版本
(Java 版本)TM7运行环境(Java 版本)“SE15. 1.7.0_45-b18) Java HotSpot(TM) 64 位服务器 VM(构建 24.45-b08,混合模式)
Is the above behavior desired behavior of getThreadAllocatedBytes
?
If so, is there no way to find effective memory on heap used by a thread.
上述行为是getThreadAllocatedBytes
? 如果是这样,是否无法在线程使用的堆上找到有效内存。
Am listing the complete program for reference:
我列出了完整的程序以供参考:
package workbench;
import java.lang.management.ManagementFactory;
import com.sun.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AnotherWorkBench {
private static final CountDownLatch latch = new CountDownLatch(4);
static final List<Long> threadIds = Collections.synchronizedList(new ArrayList<Long>());
private void dummyJob() {
List<Long> primes = new ArrayList<Long>();
long i = 0;
while (true) {
primes.add(++i);
if ((i % 10) == 0) {
primes.clear();
//introduce sleep to prevent process hogging
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(AnotherWorkBench.class.getName()).log(Level.SEVERE, null, ex);
}
System.runFinalization();
System.gc();
}
}
}
private void runDummyJobs() {
Runnable dummyJob = new Runnable() {
@Override
public void run() {
threadIds.add(Thread.currentThread().getId());
latch.countDown();
dummyJob();
}
};
Runnable memoryMonitorJob = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : Monitor thread started");
ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
threadMxBean.setThreadAllocatedMemoryEnabled(true);
while (true) {
for (Long threadId : threadIds) {
System.out.println(Thread.currentThread().getName() + " : Thread ID : " + threadId + " : memory = " + threadMxBean.getThreadAllocatedBytes(threadId) + " bytes");
}
//wait between subsequent scans
try {
System.out.println(Thread.currentThread().getName() + " : secondary sleep");
Thread.currentThread().sleep(5000);
System.out.println(Thread.currentThread().getName() + " : out of secondary sleep");
} catch (InterruptedException ex) {
Logger.getLogger(WorkBench.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
Executors.newSingleThreadExecutor().submit(dummyJob);
Executors.newSingleThreadExecutor().submit(dummyJob);
Executors.newSingleThreadExecutor().submit(dummyJob);
Executors.newSingleThreadExecutor().submit(dummyJob);
try {
latch.await();
} catch (InterruptedException ex) {
Logger.getLogger(AnotherWorkBench.class.getName()).log(Level.SEVERE, null, ex);
}
Executors.newSingleThreadExecutor().submit(memoryMonitorJob);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new AnotherWorkBench().runDummyJobs();
}
}
采纳答案by Chris K
To my knowledge, there is no reliable way to do this at runtime. And as pointed out in the source question, the heap is a shared resource and thus the heap size of a single thread does not make sense as it will overlap with objects references from other threads.
据我所知,在运行时没有可靠的方法来做到这一点。正如源问题中所指出的,堆是共享资源,因此单个线程的堆大小没有意义,因为它会与来自其他线程的对象引用重叠。
That said, when I do want to know the 'retained' sizeof a single thread, and yes retained size is a different but similar metric to the one that you asked for, then I do it by taking a heap dump and then using MAT (http://www.eclipse.org/mat/).
也就是说,当我确实想知道单个线程的“保留”大小时,是的,保留大小与您要求的指标不同但相似,然后我通过进行堆转储然后使用 MAT 来实现(http://www.eclipse.org/mat/)。
I have known people to use Java Agents to instrument the allocation of objectsand then to use a weak reference to monitor when it gets GC'd. However the performance impact of doing this is high. Very high.
我知道人们使用Java 代理来检测对象的分配,然后使用弱引用来监视它何时被 GC。但是,这样做对性能的影响很大。很高。
You may be best off using a heuristic at runtime and unit testing to ensure that memory stays within bounds. For example, you could use JMX to monitor the heap sizes and when you see the old gen growing then you can raise an alert. Using getThreadAllocatedBytes to calculate rate of allocation could also be useful.
您最好在运行时和单元测试中使用启发式方法来确保内存保持在界限内。例如,您可以使用 JMX 来监控堆大小,当您看到旧的 gen 增长时,您可以发出警报。使用 getThreadAllocatedBytes 计算分配率也很有用。
Good run time monitoring tools: appdynamics, newrelic, visualvmand yourkit
良好的运行时间监控工具: appdynamics,NewRelic的,VisualVM的和yourkit
For offline memory analysis, matand jclarityare very good.
A very useful tool to help one spot whether there is a leak, or at least is running different to expectations is to print a count of how many instances of each class are currently on the heap: jcmd <pid> GC.class_histogram.
一个非常有用的工具可以帮助人们发现是否存在泄漏,或者至少运行是否与预期不同,是打印每个类的当前在堆上的实例数量: jcmd <pid> GC.class_histogram。
回答by DavidPostill
Java VisualVMcan be used "to monitor a local application and view real-time, high-level data on the memory heap, thread activity, and the classes loaded in the Java Virtual Machine (JVM). Monitoring an application imposes low overhead and can be used for extended periods."
Java VisualVM可用于“监视本地应用程序并查看有关内存堆、线程活动和 Java 虚拟机 (JVM) 中加载的类的实时高级数据”。监视应用程序的开销很低,并且可以长期使用。”
See also How to monitor Java memory usage?for other possibilities.
另请参阅如何监视 Java 内存使用情况?对于其他可能性。