谈到JAVA虚拟机内存区域,首先简略谈下什么是JAVA虚拟机?
0、JAVA虚拟机为何物,它存在的必要性是什么?
JAVA虚拟机简称JVM理解也就是一种虚拟的计算机,如同装有操作系统的真实电脑,对!就是它,只不过JVM是虚拟出来的一台计算机而已。
JAVA代码的执行的大概流程:代码运行在--》JVM(虚拟机)--》真实的硬件机器
之所以在代码层次上不直接运行在真实的硬件计算机上,而是中间增加了JVM的环节,是因为各个硬件厂商都解析命令都可能不太一样,这样导致如果一个JAVA程序在一台硬件系统中能运行起来,但换另外一台可能就会有问题。
SUN团队通过给中间增加了一层虚拟机JVM通过这层屏蔽各个硬件厂商的不同执行,不管在哪个平台下运行同一套程序,都能正常运行,这么优渥舒服的环境就是SUN团队大仙们帮我们屏蔽掉的,让我们无需关系硬件平台的不一致性,更加关注应用程序业务,更方便的实现应用程序,当然从而也就JAVA语言实现了跨平台咯。但也同时带来副作用就是效率问题,这也是肯定的,任何事情没有绝对的好坏,JAVA程序慢。当然因为他中间还要经过JVM当然相对慢了啊,这也可以理解。
下面我们回归标题的内容 JAVA 虚拟机内存区域与内存溢出理解
1、JAVA 虚拟机内存区域:
既然JVM是JAVA语言的一个虚拟的计算机,那么虚拟的计算机肯定就有虚拟的内存咯?(屁话,当然!谁家电脑没有内存啊!) 只不过JAVA内存会比物理机内存里面划分的更细一点。JVM内存,我们大多数人也经常听到的两个内存就是堆、栈。其实不然,JVM还有更细腻的划分,跟大家一起探讨分享下:
JVM运行时的内存划分:
a) . 堆;
b) . 栈;
c) . 方法区域;
d) . 程序计数器。
这是以SUN官方的虚拟机HotSpot为例说明,当然还有其他各个NX公司在开源的基础之上形成自己的虚拟机,这里我也没了解。我们就以官方HotSpot为例说明内存分配问题。
堆内存区域:存放所有实例化后的对象都在这里,它是所有内存区域里面空间最大的一块。重量级(属于多个线程共享的区域);
栈内存区域:存放所有实例化后的对象引用,包括方法里面局部变量等;
方法内存区域:存放类的信息,方法地址等;
程序计数器区域:存放各个线程执行代码的行号标记。CPU在一个时间点上来只能执行一个线程,那么到下一个时间点就可能执行另一线程,这时候JVM就会用该区域记录下当前线程执行的字节码行号多少,不至于下次调转回来错乱掉。
2、内存溢出
先梳理下大家的困惑、或者是我之前的困惑。JAVA方面让我们听的最多的内存溢出的同时跟它对应的,就是内存泄露啦。 那么他两者到底有什么区别个人拙见如下:
内存泄露:是指内存里面有程序用没有使用或引用,或永久不会使用的对象,垃圾回收器(因为垃圾回收机使用的root, 目标可达策略回收的)回收不到这些对象,这种就是内存泄露,内存泄露只是一个内存溢出的中间过程。内存泄露到一定程度并且该对应内存也没办法扩充了,JVM就报出:OutOfMemoryError错误。
内存溢出:有两种情况,一种是没有不可用对象存在于内存中,就只是内存设置太小了,当创建对象太多,就OutOfMemoryError错误;另一种情况,由于内存泄露所引起的内存溢出导致:OutOfMemoryError
解决内存溢出的方案:
可使用java自带的内存映像工具%JAVA_HOME%/bin/jconsole.exe,检测查看内存情况,分析到底是内存本身设置不够还是由于内存泄露引起的溢出。
如内存本身设置不够,网上对应JVM内存设置一大坨,将内存改大点就行;如是内存泄露导致的内存溢出那么就要排查应用程序代码行中那些业务可能涉及到占用内存过多且不能被GC回收的对象,将修改其代码解决溢出问题。
以上只是个人理论的理解,欢迎不同的朋友予以指正,共同学习,感谢!