《深入理解java虚拟机》笔记——1.内存结构&实例化对象过程

1.JDK与JRE?

JDK,全称Java Development Kit,即Java程序开发工具包;包含了JRE,Java API类库和Jvm;

JRE,全称Java Runtime Environment,即Java运行时环境,包括Java API子集和Jvm;

JVM,全称Java Virtual Machine,即Java虚拟机,java实现跨平台(一次编译,多处运行)的基础;

2.Java内存结构(运行时数据区域)

image.jpeg

1.程序计数器,线程私有,当前java程序执行的字节码的“行号指示器”;线程的跳转、恢复都依赖这个程序计数器;对于Java方法,程序计数器记录的是虚拟机字节码指令的地址;对于本地方法(通过JNI,Java Native Interface),程序计数器为null;

2.java虚拟机栈,线程私有,每一个java方法的执行都会创建一个“栈帧”,这个栈帧记录了方法的局部变量表,操作数,动态链接,方法出口;方法的执行到返回可以看作是一个“入栈到出栈”的过程;

既然是“栈”,就有栈的深度,对于一个线程,当线程请求栈深度大于虚拟机所规定的深度,如方法递归造成,则会抛出StackOverflowError异常;对于多个线程,由于每个线程执行方法时都会分配栈空间,当虚拟机栈请求扩展却无法申请到足够的内存,则抛出OutOfMemory异常。

3.本地方法栈,线程私有,对应于java虚拟机栈,只不过所执行的方法换成了Native本地方法;

4.java堆,线程公有,java内存管理中最大的一块,主要是用来放实例对象的;也是Jvm垃圾回收主要针对的一块内存区域,java堆针对分代回收算法,分为了新生代New(新生代包括1个Eden和两个相同大小的Survivor区,默认8:1:1),老年代Old;

5.方法区,线程公有,方法区存放跟类相关的数据,包括已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码;这个区域的垃圾回收主要是针对“常量池”和对“已加载类的卸载”。

最常见的OOM情况有以下三种:

  • java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
  • java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
  • java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。

补充——参数配置命令

(1)堆设置

  • -Xms :初始堆大小(此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存)
  • -Xmx :最大堆大小
  • -Xmn:设置年轻代大小
  • -Xss:设置每个线程的堆栈大小(创建线程时内存不够,栈溢出)
  • -XX:NewRatio=n: 设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
  • -XX:SurvivorRatio=n :年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
  • -XX:MaxPermSize=n :设置持久代大小(永久代,如常量池溢出或加载太多类)

(2)收集器设置

  • -XX:+UseSerialGC :设置串行收集器
  • -XX:+UseParallelGC :设置并行收集器
  • -XX:+UseParalledlOldGC :设置并行年老代收集器
  • -XX:+UseConcMarkSweepGC :设置并发收集器

3.new一个对象的过程?

  1. 检查;检查能否在常量池定位到一个类的符号引用;检查这个类有没有被加载过,若没有,则加载这个类;
  2. 分配内存;在java堆中,为当前类的对象分配一块足够大的内存;分配内存的方式有两种:“指针碰撞”和“空闲列表”;
    指针碰撞:认为内存空间是规整的,即被使用的内存在一边,空闲的内存在另一边,交界处有一个指针,当通过向空闲的一方移动指针来实现内存的分配;
    空闲列表:认为内存空间不连续,不规整,用一个列表记录哪些内存片段可用,分配内存时则从列表里面找出一块足够大的空闲的空间来分配;
  3. 初始化;真正意义上的执行代码中的“初始化”操作;

4.如何访问对象?(2种方式)

1.通过句柄;java堆划分一块内存作为“句柄”;reference存储句柄地址的地址,而句柄本身包含了“对象示例数据”和“类型数据”的地址,通过“对象示例数据”可以访问对象;(当对象移动,实例对象的地址改变,而reference本身不会改变)

2.通过指针;即就、指针存放“对象示例数据”,直接指向对象,访问速度快;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值