JVM二运行时数据区

打印 上一主题 下一主题

主题 968|帖子 968|积分 2904




分代收集理论:当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(GenerationalCollection)的理论举行设计,分代收集名为理论,实质是一套符合大多数程序运行实际环境的经验法则,它建立在两个分代假说之上:


  • 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。
  • 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以灭亡。
这两个分代假说共同奠定了多款常用的垃圾收集器的一致的设计原则:收集器应该将Java堆划分出差别的区域,然后将回收对象依据其年岁(年岁即对象熬过垃圾收集过程的次数)分配到差别的区域之中存储。


  • 如果一个区域中大多数对象都是朝生夕灭,难以熬过垃圾收集过程的话,那么把它们集中放在一起,每次回收时只关注怎样保留少量存活而不是去标记那些大量将要被回收的对象,就能以较低代价回收到大量的空间;
  • 如果剩下的都是难以灭亡的对象,那把它们集中放在一块,虚拟机便可以使用较低的频率来回收这个区域。
这就同时分身了垃圾收集的时间开销和内存的空间有用使用。
内存模子变迁:
JDK1.7:


  • Young 年轻区 :紧张保存年轻对象,分为三部门,Eden区、两个Survivor区。
  • Tenured 大哥区 :紧张保存年长对象,当对象在Young复制转移肯定的次数后,对象就会被转移到Tenured区。
  • Perm 永久区 :紧张保存class、method、filed对象,这部份的空间一样平常不会溢出,除非一次性加载了很多的类,不外在涉及到热摆设的应用服务器的时候,偶尔候会遇到OOM ermGen space 的错误。
  • Virtual区: 最大内存和初始内存的差值,就是Virtual区。
JDK.1.8:
​ 由2部门组成,新生代(Eden + 2*Survivor ) + 大哥代(OldGen ) JDK1.8中变化最大是,的Perm永久区用Metaspace举行了替换注意:Metaspace所占用的内存空间不是在虚拟机内部,而是在当地内存空间中
JDK1.9:
​ 取消新生代、老年代的物理划分
​ 将堆划分为若干个区域(Region),这些区域中包罗了有逻辑上的新生代、老年代区域
虚拟机栈

栈帧(Stack Frame)是用于支持虚拟机举行方法执行的数据结构。
栈帧存储了方法的局部变量表操纵数栈、动态毗连和方法返回地址等信息。每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。
栈内存为线程私有的空间,每个线程都会创建私有的栈内存,生命周期与线程相同,每个Java方法在执行的时候都会创建一个栈帧(Stack Frame)。栈内存大小决定了方法调用的深度,栈内存过小则会导致方法调用的深度较小,如递归调用的次数较少。
栈异常的两种环境
如果线程请求的栈深度大于虚拟机所允许的深度(Xss默认1m),会抛出StackOverflowError异常
如果在创建新的线程时,没有足够的内存去创建对应的虚拟机栈,会抛出OutOfMemoryError异常【不愿定】
当地方法栈

   当地方法栈和虚拟机栈相似,区别就是虚拟机栈为虚拟机执行Java服务(字节码服务),而当地方法栈为虚拟机使用到的Native方法(比如C++方法)服务
  方法区

方法区(Method Area)是可供各个线程共享的运行时内存区域,方法区本质上是Java语言编译子女码存储区域,它存储每一个类的结构信息,比方:运行时常量池、成员变量、方法数据、构造方法宁静凡方法的字节码指令等内容。很多语言都有雷同区域。
方法区的具体实现有两种:永久代(PermGen)、元空间(Metaspace)
永久代和元空间的区别是什么?

  • JDK1.8之前使用的方法区实现是永久代,JDK1.8及以后使用的方法区实现是元空间。
  • 存储位置差别:
    永久代所使用的内存区域是JVM进程所使用的区域,它的大小受整个JVM的大小所限制。
    元空间所使用的内存区域是物理内存区域。那么元空间的使用大小只会受物理内存大小的限制。
  • 存储内容差别:
    永久代存储的信息基本上就是上面方法区存储内容中的数据。
    元空间只存储类的元信息,而静态变量和运行时常量池都挪到堆中。

字符串常量池

1)三种常量池的比较
class常量池:一个class文件只有一个class常量池
字面量:数值型(int、float、long、double)、双引号引起来的字符串值等
符号引用:Class、Method、Field等
运行时常量池:一个class对象有一个运行时常量池
字面量:数值型(int、float、long、double)、双引号引起来的字符串值等
符号引用:Class、Method、Field等
字符串常量池:全局只有一个字符串常量池
双引号引起来的字符串值

2)字符串常量池怎样存储数据?
为了进步匹配速率, 即更快的查找某个字符串是否存在于常量池 Java 在设计字符串常量池的时候,还搞了一张StringTable, StringTable内里保存了字符串的引用。StringTable雷同于HashTable(哈希表)。在JDK1.7+,StringTable可以通过参数指定-XX:StringTableSize=99991
字符串常量池怎样查找字符串:
根据字符串的hashcode找到对应entry
如果没有冲突,它大概只是一个entry
怎样有冲突,它大概是一个entry的链表,然后Java再遍历链表,匹配引用对应的字符串
如果找到字符串,返回引用
如果找不到字符串,在使用intern()方法的时候,会将intern()方法调用者的引用放入到stringtable

程序计数器

程序计数器(Program Counter Register),也叫PC寄存器,是一块较小的内存空间,它可以看作是当火线程所执行的字节码指令的行号指示器。字节码解释器的工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。分支,循环,跳转,异常处理,线程回复等都需要依赖这个计数器来完成。
为什么需要程序计数器?
由于Java虚拟机的多线程是通过线程轮替切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(针对多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换(系统上下文切换)后能规复到精确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
存储的什么数据?
如果一个线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是一个Native方法,这个计数器的值则为空。
**异常:**此内存区域是唯逐一个在Java的虚拟机规范中没有规定任何OutOfMemoryError异常环境的区域。
直接内存

直接内存并不是虚拟机运行时数据区的一部门,也不是Java 虚拟机规范中界说的内存区域。在JDK1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用native 函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer 对象作为这块内存的引用举行操纵。这样能在一些场景中显著进步性能,因为避免了在Java堆和Native堆中来回复制数据。本机直接内存的分配不会受到Java 堆大小的限制,受到本机总内存大小限制。
直接内存(堆外内存)与堆内存比较:


  • 直接内存申请空间耗费更高的性能,当频繁申请到肯定量时尤为显着
  • 直接内存IO读写的性能要优于平凡的堆内存,在多次读写操纵的环境下差异显着
为什么会是这样?
从数据流的角度,来看
非直接内存作用链:当地IO –>直接内存–>非直接内存–>直接内存–>当地IO
直接内存作用链:当地IO–>直接内存–>当地IO
直接内存的使用场景:
有很大的数据需要存储,它的生命周期很长
得当频繁的IO操纵,比方:网络并发场景

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表