[jjzhu学java]深入理解JVM笔记之内存管理机制

  • 时间:
  • 浏览:5

JVM栈也是每个任务管理器运行所私有的内存区域,随着任务管理器运行的创建而分配,任务管理器运行的消亡而回收。JVM栈是描述Java法子执行的内存模型,每个java法子在执行的完后 ,就有创建一2个多 栈帧(Stack Frame),其作用是用来保存java法子中的局部变量、操作栈、法子出口等信息。每一2个多 java法子从被调用到执行完毕的过程,都伴随着对应的栈帧在JVM栈中的进栈和入栈。

JVM规范中,该区域包含一2个多 异常情况:

-StackOverflowError:任务管理器运行请求的栈深度1超过了JVM栈所允许的栈深度1

-OutOfMemoryError:肯能JVM栈是动态可扩展的,在无法申请到足够内存时,抛出该异常

并配置运行时的VM参数:



这里-XX:UseParNewGC是指定用ParNew下发器,默认的是

参数解释: -Xms:20M:java堆最小20M

-Xmx:20M:java堆最大20M(除理动态扩展)

-XX:+HeapDumpOnOutOfMemoryError:开启该选项,可不都可否让虚拟机在抛出OutOfMemoryError时Dump出当前内存堆转存快照

运行后,就会有如下输出:

法子区(Method Area)也是各任务管理器运行共享的内存区域,用于存储被虚拟机加载的类信息、常量、静态常量、编译后的代码等数据看,其还有一2个多 别名叫Non-Heap(非堆),与java堆加以区分。在HotSpot虚拟机上,也可叫做“永久代”(Permanent Generation),本质上不等价(HotSpot将GC下发扩展到了该区域)。

若要对该区域进行GC,主这人这人我回收常量池以及对类型的卸载。该区域在内存满后也会抛出OOMError异常。

直接内存(Direct Memory)就有虚拟机运行时数据区域的一每段,也就有JVM规范中定义的内存区域,但其也频繁被使用。自JDK1.4后,引入了基于通道(Channel)与缓冲区的I/O法子,它可不都可否使用native函数库直接分配堆外内存,并通过java堆中的DirectByteBuffer对象操作该块内存。除理了java堆和native堆之间的数据克隆qq,提高了性能。

本机直接内存不受java堆大小限制,过后受本机总内存大小和除理器的寻址空间限制。在动态扩展时也会抛出OOMError异常。

String.intern()法子可不都可否向运行时常量池中去掉 内,这人这人要达到运行时常量池溢出,执行用本地法子intern()像池中不断去掉 字符串即可,可不都可否同过-XX:PermSize -XX:MaxPermSize限制法子区大小。

完后 有提过,HotSpot虚拟机并这么区分JVM和本地法子栈。在HotSpot虚拟机中可不都可否通过制定-Xss参数来指定栈的大小。

编写如下测试代码:

完后 对虚拟机运行时数据区域进行了描述,现在通过实例来验证OOM异常处于的情况,可不都可否进一步了解jvm各内存区域的存储内容,及处于异常的情况。

测试的java版本为:

运行时常量池(Runtime Constant Pool)是法子区内的一每段,Class文件中除了类的版本、字段、法子、接口等描述信息,还常量池表,用于存放编译期间生成的葛总常量和符号引,这每段内容在类加载后存放运行时常量池你这人(class咋样加载会在后边章节提及)。运行时常量池具备动态性,java语言不单单在编译期间会产生常量,在运行期间也肯能将新的常量放入去去去运行时常量池中,如开发人员用了String.intern()法子,完后 的异常测试这人这人我用该法子引起常量池抛出OOMError。

Java堆是java虚拟机所管理的最大的内存区域,他们 所说的垃圾回收,这人这人我对该区域的内存进行回收,这人这人也叫GC堆。java堆是所有任务管理器运行所公用的内存区域,任务管理器运行中的对象、数组都存放入去去去该区域中。

从内存回收的深度1来看,肯能现在的下发器所采用的就有分代下发算法,这人这人java堆可不都可否在进一步细分为:新生代和老年代,在新生代中,又可不都可否划分为Eden、From survivor、To survivor等空间。从内存分配的深度1来看,java堆肯能划分为多个任务管理器运行私有的分配缓存区。

java堆能是否物理上不连续但逻辑上要连续的内存空间,可不都可否通过指定-Xmx(最大)、-Xms(最小)、-Xmn(新生代)等VM参数来设置java堆得大小。若有新对象申请内存空间过后java堆这么足够的内存分配时,会报OOMError。

每个任务管理器运行就有一2个多 任务管理器运行计数器(PC),是当前任务管理器运行所执行的字节码的行号指示器,通过改变任务管理器运行计数器的值来选泽下两根指令。各任务管理器运行之间的计数器互不影响,是任务管理器运行私有的内存。

肯能任务管理器运行执行的是一2个多 JAVA法子,则计数器记录的为正在执行的字节码指令的地址,肯能执行的是Natvie法子,这计数器的值为空(Undifined)。

任务管理器运行计算器所在的内存区域是唯一一2个多 JVM规范中这么规定OOMError的内存区域

完后 肯能提到,对象实例都存储在java堆中,这人这人可不都可否不断的创建对象且保证对象不被GC就可不都可否让java堆溢出

编写如下代码清单:

本机直接内存可不都可否通过 -XX:MaxDirectMemorySize指定内存大小,若不指定,则默认与java堆得最大值一样。

java version “1.7.0_50”

Java(TM) SE Runtime Environment (build 1.7.0_50-b15)

Java HotSpot(TM) 64-Bit Server VM (build 24.50-b11, mixed mode)

本地方栈(Native Method Stack)是描述虚拟机所用到的本地法子的内存模型,与JVM栈这人,也会抛出StackOverflowError和OutOfMemoryError

运行后就会报StackOverflowError异常: