您的位置:首页 > 其它

JVM 内存结构

2014-02-23 16:22 204 查看

1.Jvm 的相关知识

1.1 Jvm的内存结构

1.1.1 jvm内存概述

1. 我们一般理解的计算机内存,它算是CPU与计算机打交道最频繁的区域,所有数据都是先经过硬盘至内存,然后由CPU再从内存中获取数据进行处理,又将数据保存到内存,通过分页或分片技术将内存中的数据再flush至硬盘。

2. JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了
.

3. java
和 c
之类的语言不同 ,
不需要开发人员来分配内存和回收内存 ,
而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收/分代回收、GC
:generational collection) ;

4. 那JVM的内存结构到底是如何呢?JVM做为一个运行在操作系统上,但又独立于os运行的平台,它的内存至少应该包括象寄存器、堆栈等区域
?

1.1.2 jvm内存结构及功能概述



下面将逐一介绍下各个区域所做的工作及其充当的功能。

1. PC寄存器( PC Register )

PC寄存器是一块很小的内存区域,主要作用是记录当前线程所执行的字节码的行号。字节码解释器工作时就是通过改变当前线程的程序计数器选取下一条字节码指令来工作的。任何分支,循环,方法调用,判断,异常处理,线程等待以及恢复线程,递归等等都是通过这个计数器来完成的。

由于Java多线程是通过交替线程轮流切换并分配处理器时间的方式来实现的,在任何一个确定的时间里,在处理器的一个内核只会执行一条线程中的指令。因此为了线程等待结束需要恢复到正确的位置执行,每条线程都会有一个独立的程序计数器来记录当前指令的行号。计数器之间相互独立互不影响,我们称这块内存为“线程私有”的内存。

如果所调用的方法为native的,则PC寄存器中不存储任何信息。

2. JVM Stack ( JVM栈 )

2-1: JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack
Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址 ,
因此Java中基本类型的变量是值传递,而非基本类型的变量是引用传递 ,
总之JVM
栈中 ,
存放局部变量的值 ,
方法中的参数值 ,
对象的引用地址 ,
当超过该变量的作用域的时候 , java
编译器自动的释放为该变量所分配的jvm的内存空间 ,
栈区中jvm的内存空间 ,
由java编译器自动分配和释放
;

2-2: 由于JVM栈是线程私有的,因此其在内存分配上非常高效,并且当线程运行完毕后,这些内存也就被自动回收。当JVM栈的空间不足时,会抛出StackOverflowError的错误,在Sun
JDK中可以通过-Xss来指定栈的大小 , Sun JDK的实现中JVM栈的空间是在物理内存上分配的
;

2-3: 栈的优势是存取速度快 ,
缺点是 ,
存在栈中的数据大小和生存期 ,
必须事先跟编译器确定 ,
灵活性差 ,
栈:堆栈是一端固定 ,
另一端会变化的特殊的存储空间 ,
我们可以把它想象成装固体的桶 ,
桶底(栈底)固定
, 桶里面所装固体的最高处定义为桶顶(栈顶) ,
如果什么都没有装时,桶顶和桶底相等 ,
所以栈是FILO(firstin last out)
先进后出 (当装一层沙子后,桶顶升高(即栈顶地址-2,相当于入栈PUSH),再装一层水泥,桶顶再次升高,(即栈顶地址又-2),当你往出倒东西的时候,你先倒出最上层的水泥,桶顶下降(即栈顶地址+2,相当出栈POP),然后你才能倒出沙
) ;

3. JVM Heap(JVM
堆)

3-1: Heap是大家最为熟悉的区域,它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收
;

3-2: Heap在32位的操作系统上最大为2G,在64位的操作系统上则没有限制,其大小通过-Xms和-Xmx来控制,-Xms为JVM启动时申请的最小Heap内存,默认为物理内存的1/64但小于1G,-Xmx为JVM可申请的最大Heap内存,默认为物理内存的1/4,默认当空余堆内存小于40%时,JVM会增大Heap的大小到-Xmx指定的大小,可通过-XX:MinHeapFreeRatio=来指定这个比例,当空余堆内存大于70%时,JVM会将Heap的大小往-Xms指定的大小调整,可通过-XX:MaxHeapFreeRatio=来指定这个比例,但对于运行系统而言,为了避免频繁的Heap
Size的大小,通常都会将-Xms和-Xmx的值设成一样,因此这两个用于调整比例的参数通常是没用的。其实jvm中对于堆内存的分配、使用、管理、收集等有更为精巧的设计.
当堆中需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

3-3: 堆的优势:java在运行的时候
, 动态的分配堆中的jvm内存的大小 ,
生存期也不必事先告诉编译器 ;

堆的缺点:在运行时动态分配jvm的内存
, 存取速度较慢 ;

4. NativeMethodStacks(本地方法堆栈)
JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。

5. JVM Method Area(方法区域)
5-1: JVM Method Area
分为 :
a:
静态区或者数据区 (data segment) ,
存放全局变量 ,
静态变量 ,
和字符串常量 ,
不释放 ;
b:
代码区 (code segment) ,
存放程序中方法的二进制代码 ,
而且多个对象共享一个代码空间区域

5-2:
方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,可见方法区域的重要性。同样,方法区域也是全局共享的,它在虚拟机启动时在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

5-2:
在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代,默认为64M,可通过-XX:PermSize以及-XX:MaxPermSize来指定其大小。
5-3: 运行时常量池(RuntimeConstant Pool)类似C中的符号表,存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。类或接口的常量池在该类的class文件被java虚拟机成功装载时分配。

在掌握了JVM对象内存分配的机制后,接下来看看JVM是如何做到自动的对象内存回收的,这里指的的是Heap以及Method
Area的回收,其他几个区域的回收都由JVM简单的按生命周期来进行管理。

http://blog.csdn.net/zhaozheng7758/article/details/8623576;
/article/10407795.html
/article/5834918.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: