为什么Java程序占用的内存比实际分配给它的要多
很多人错误的认为运行Java程序时使用-Xmx和-Xms参数指定的就是程序将会占用的内存,但是这实际上只是Java堆对象将会占用的内存。堆只是影响Java程序占用内存数量的一个因素。要更好的理解你的Java程序将会占用多大的内存需要先了解有哪些因素会影响到内存的占用。这些因素包括:
- 对象(Objects)
- 类(Classes)
- 线程(Theads)
- 本地数据结构(Native data structures)
- 本地代码(Native code)
每个因素对内存占用的影响又会随着应用程序、运行环境和系统平台的不同而变化,那怎样计算总的内存占用量?是的,想得到一个准确的数字不是那么容易,因为你很难控制本地(Native)部分。你能控制的部分只有堆大小:-Xmx,类占用的内存:-XX:MaxPermSize,还有线程栈:-Xss控制每个线程占用的内存。注意当把栈大小设置的太小时会导致StackOverflow异常、程序出错。所以,计算公式为:
(-Xmx) + (-XX:MaxPermSize) + 线程数 * (-Xss) + 其它内存
其它内存部分取决于本地代码占用的内存,如NIO、socket缓冲区、JNI等。它一般大约是jvm内存的5%左右。所以假设我们有下面的JVM参数和100个线程:
-Xmx1024m -XX:MaxPermSize=256m -Xss512k
那么jvm进程至少会占用内存数量为:1024m + 256m + 100*512k + (0.05 * 1330m) = 1396.5m
我一般使用(1.5 * 堆最大值)来作为一个近似值表示一个tomcat进程会需要的最小内存,如果你有需要增加MaxPermSize到256M以上的应用这个值可以更大些。如果你使用这个来衡量你的系统将会占用多少内存要记住你需要为系统和其它运行在系统上的程序留下足够的内存,否则会导致系统使用过多的虚拟内存,这样会降低性能。
不光是Java,任何依托在OS上执行的程序,OS所分配的内存都要大于程序内部自己申请的内存.很简单的道理,你不是一个人再战斗,程序的运行牵涉到方方面面,你写的代码只是其中的一个环节.托管语言更不可控.
我觉得Java把主要精力放到堆上是和它的gc相关,与线程相关的内存生命周期短。可能和主题不相干,看完之后想到的,就回复了。
空间换时间 。
如果内存很小的话 你看看JIT 还能不能那么强大 当然 是JIT可以跑起来的环境 但是内存小。
就是说除了程序所占用的内存,还有一个虚拟机在消耗内存。
Java所编写的程序在运行的时候占用内存是否真的很大了?“java程序运行的时候占用内存很大”我相信只要接触IT这个行业的人大部分的人都会毫不犹豫回答java程序运行的时候占用内存很大。也是许多java程序员默认的说法。在这里在这里我想在这里说下。
和许多程序员一样我也从c转到java的。由于c是公认的最接近机器语言的,而大部分程序员都会c语言。所以这里我用c与java进行测试比较结果。测试环境:计算机:P4,CPU:2.1GHz;内存:2G;jdk:1.7
测试:为了让效果精确,我特意让c和java两个程序所实现的功能语句尽量相同,在所写的行数上也力求一致。除此之外最重要的是让程序能裸奔。好啦,我相信大家和我一样迫不及待了吧,现在让我们来开始测试:
java:
public class JavaTest{
public static void main(String[] args){
for(int i=1;i<100000;i++){
for(int j=1;j<100000;j++){
}
}
}
}
现在我们在CMD中键入:java JavaTest<回车>,然后打开“任务管理器”可以看到这个程序占用内存“4910K”,也许大家看到这里还是觉得它占用内存很大。不要急的,我们再在CMD中键入:java @##@¥<回车>,这个是故意输错参数的,应为这个是java.exe本身运行的时候占用的内存,这个时候我们在看“任务管理器”显示进程占用内存为“4371K”。
那么这个程序到底占用内存多少了?4910K-4371K=539K.
好啦,我们现在来看看c程序运行的结果:
c:
int main (int argc,char* argv[])
{
for(int i=1;i<100000;i++){
for(int j=1;j<100000;j++){
}
}
return 0;
}
我们用vc++6.0编译运行,同样查看“任务管理器”程序占用内存情况。
可以看出内存为“675K”.
测试结果:总体来看,java进程“4910K”的确比c进程的“675K”多占用几倍内存。但是如果除去java本身所占用的内存,那么,这个java进程所占用内存实际占用比c进程占用内存还小,哈哈。。可能说道这里大家都不相信,呵呵。。。可是这是事实,大家如果不相信可以亲自测试下,那么大家可能要问那么java本身的占用内存那么大为什么啊?呵呵。。。只要大家看看sun公司开发java语言的目标和优点,就知道为什么啦,这个介绍就不具体时候了,网上有许多解释的文章,大家有需要可以上网了解一下。在这里另外说明一点的就是c能做的事情java也能做到,并且能很快做到,做的很好。除了很底层的事情:驱动、原始套接字(相信以后sun会提供)、系统级的程序(谁让系统是用c开发的了)。以后大家在看见有人说java占的内存多就可以辩论下了!同时也可以让大家明白凡事要自己求证,尤其作为程序员!
java占用大,是因为jvm、gc机制和oop造成的。
你这个简单的循环打印,因为有常量池的存在所以内存占用不明显,这是jvm对于自我的优化。
c++的很多方面都由自己手动和编译器控制,所以一个优秀的程序员和一个优秀的c++编译器同样重要。
而java把这方面更多的交由jvm控制,释放了程序员的压力,降低了程序员的门槛。
----------------------------------------------------------------------------------------------------
这个测试实例,是最简单的100000*100000次的循环,这个里面没有涉及到人工的任何优化,虽然jvm和c++编译器都会进行优化,对于这个内部优化谁的说不清楚在某种情况下谁优化的更好,现在很多的高级语言,很多都是基于c做起来的,所以暂时假设两种优化效果一样!很多客观的原因不能考虑一样,但是我们尽量做到一样、、、哈、、、这个也是做一定的探索、、、
---------------------------------------------------------------------------
在这里另外说明一点的就是c能做的事情java也能做到,并且能很快做到,做的很好。除了很底层的事情:驱动、原始套接字(相信以后sun会提供)、系统级的程序(谁让系统是用c开发的了)。这叫C能做的事情Java都可以做?那C可以写JVM.Java能写JVM么?就是因为Java干不了C的活所以才用C来做。另外内存占用C是可以调整的在PE结构里面就可以修改。Java可以修改么?单纯循环。vc连接器里面可以指定输出的可执行文件默认内存。最小可以优化到1k。非要比这个那就比吧讨厌那些Javaer总是自以为是的认为Java无敌的思想。如果你想要承认自己无敌你就要做出一些让别人信服的。C内存占用大那是系统分配给他就这么大。堆栈本身就需要占用。这个是可以优化掉的。JVM你可以优化掉么?优化掉Java怎么执行?所以被自欺欺人了。Java本来就以牺牲运行性能和内存为代价来模拟跨平台的。没人说错了。开发效率挺高的。这点牺牲也很值得。