jvm堆内存管理有关

来源:互联网 发布:js 控制重新打开页面 编辑:程序博客网 时间:2024/05/16 02:47
http://blog.csdn.net/kobejayandy/article/details/8496651

四、Heap 堆


Heap(堆)是JVM的内存数据区。Heap 的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在Heap 中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。

Java中堆是由所有的线程共享的一块内存区域。

4.1 Generation


JVM堆一般又可以分为以下三部分:

Perm

Perm代主要保存class,method,filed对象,这部门的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。

Tenured

Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。

Young

Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Young区间变满的时候,minor GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。

4.2 Sizing the Generations


JVM提供了相应的参数来对内存大小进行配置。正如上面描述,JVM中堆被分为了3个大的区间,同时JVM也提供了一些选项对Young,Tenured的大小进行控制。

Total Heap

-Xms :指定了JVM初始启动以后初始化内存

-Xmx:指定JVM堆得最大内存,在JVM启动以后,会分配-Xmx参数指定大小的内存给JVM,但是不一定全部使用,JVM会根据-Xms参数来调节真正用于JVM的内存

-Xmx -Xms之差就是三个Virtual空间的大小

Young Generation

-XX:NewRatio=8意味着tenured 和 young的比值8:1,这样eden+2*survivor=1/9

堆内存

-XX:SurvivorRatio=32意味着eden和一个survivor的比值是32:1,这样一个Survivor就占Young区的1/34.

-Xmn 参数设置了年轻代的大小

Perm Generation

-XX:PermSize=16M -XX:MaxPermSize=64M

Thread Stack

-XX:Xss=128K

加载类。第 4 步,加载类。由于没有指定加载器,JVM 默认使用 bootstrap 加载器,就把 rt.jar 下的所有
类都加载到了堆类存的永久存储区,自定义类也被加载到内存中

具体的说原生数据类型传递的值,引用类型传递的地

 向操作系统申请空闲内存。JVM 对操作系统说“给我 64M 空闲内存”,于是第 1 步,JVM 向操作系统申请空闲内存
作系统就查找自己的内存分配表,找了段 64M 的内存写上“Java 占用”标签,然后把内存段的起始地址和终止地址给 JVM,JVM 准备加载类文件

问:为什么会产生 OutOfMemory 产生?
答:一句话:Heap 内存中没有足够的可用内存了。这句话要好好理解,不是说 Heap 没有内存
了,是说新申请内存的对象大于 Heap 空闲内存,比如现在 Heap 还空闲 1M,但是新申请的内存需
要 1.1M,于是就会报 OutOfMemory 了,可能以后的对象申请的内存都只要 0.9M,于是就只出现
一次 OutOfMemory,GC 也正常了,看起来像偶发事件,就是这么回事。 但如果此时 GC 没有回
收就会产生挂起情况,系统不响应了。

问:我产生的对象不多呀,为什么还会产生 OutOfMemory?我产生的对象不多呀,?
答:你继承层次忒多了,Heap 中 产生的对象是先产生 父类,然后才产生子类,明白不?
            错误分几种?问:OutOfMemory 错误分几种?
答:分两种,分别是“OutOfMemoryError:java heap size”和”OutOfMemoryError: PermGen
space”,两种都是内存溢出,heap size 是说申请不到新的内存了,这个很常见,检查应用或调整
堆内存大小。
“PermGen space”是因为永久存储区满了,这个也很常见,一般在热发布的环境中出现,是
因为每次发布应用系统都不重启,久而久之永久存储区中的死对象太多导致新对象无法申请内存,
一般重新启动一下即可。

问:为什么会产生 StackOverflowError??
答:因为一个线程把 Stack 内存全部耗尽了,一般是递归函数造成的。

问:一个机器上可以看多个 JVM 吗?JVM 之间可以互访吗?
答:可以多个 JVM,只要机器承受得了。JVM 之间是不可以互访,你不能在 A-JVM 中访问
B-JVM 的 Heap 内存,这是不可能的。

问:JVM 中到底哪些区域是共享的?哪些是私有的?
答:Heap 和 Method Area 是共享的,其他都是私有的,

问:什么是 JIT,你怎么没说?,你怎么没说?
答:JIT 是指 Just In Time,有的文档把 JIT 作为 JVM 的一个部件来介绍,有的是作为执行引
擎的一部分来介绍,这都能理解。Java 刚诞生的时候是一个解释性语言,别嘘,即使编译成了字
节码(byte code)也是针对 JVM 的,它需要再次翻译成原生代码(native code)才能被机器执行,于
是效率的担忧就提出来了。Sun 为了解决该问题提出了一套新的机制,好,你想编译成原生代码,
没问题,我在 JVM 上提供一个工具,把字节码编译成原生码,下次你来访问的时候直接访问原生
码就成了,于是 JIT 就诞生了,就这么回事。

问:JVM 还有哪些部分是你没有提到的?
答:JVM 是一个异常复杂的东西,写一本砖头书都不为过,还有几个要说明的:
常量池(constant pool)按照顺序存放程序中的常量,:并且进行索引编号的区域。比如 int i =100,
这个 100 就放在常量池中。
安全管理器(Security Manager):提供 Java 运行期的安全控制,防止恶意攻击,比如指定读取
文件,写入文件权限,网络访问,创建进程等等,Class Loader 在 Security Manager 认证通过后才
能加载 class 文件的。
方法索引表(Methods table),记录的是每个 method 的地址信息,Stack 和 Heap 中的地址指针
其实是指向 Methods table 地址。

问:为什么不建议在程序中显式的生命 System.gc()??
答:因为显式声明是做堆内存全扫描,也就是 Full GC,是需要停止所有的活动的(Stop The
World Collection),你的应用能承受这个吗?

问:JVM 有哪些调整参数?
答:非常多,自己去找,堆内存、栈内存的大小都可以定义,甚至是堆内存的三个部分、新生
代的各个比例都能调整。

0 0
原创粉丝点击