JVM内存管理

一. JVM内存

1. jvm内存模型

在这里插入图片描述

在JDK1.8之后方法区就被删除,并且在直接内存中添加了元空间。

在这里插入图片描述

2. 详细说明

线程私有区域:

  • 虚拟机栈
  • 本地方法栈
  • 程序计数器

线程共享区域:

  • 方法区
  • 直接空间
2.1 程序计数器

​ 程序计数器是用来存放下一条指令所在单元的地址的地方。分支、循环、跳转等功能都需要程序计数器来来完成,每个线程都有一个程序计数器,各个线程的程序计数器互不干扰,并且线程之间切换后回到正确的执行位置都需要程序计数器来完成。

2.2 虚拟机栈

​ 虚拟机栈由一个个栈帧所组成,也是线程私有的,描述的是方法执行的内存模型,每次方法调用的数据都是通过栈传递的,会出现两种错误StackOverFlowErrorOutOfMemoryError

2.3 堆

​ 堆是JVM内存中最大的一块,是所有线程共享的区域,在JVM启动的时候创建,几乎所有的实例对象和数组都在这里存放,是垃圾收集管理的主要区域。从垃圾收集算法的角度来看,堆又可以细分为新生代和老年代,或者再细分为Eden、From Survivor、To Survivor等。

在这里插入图片描述

JDK1.8之间堆通常分为新生代、老年代、永生代(HotSpot的方法区),JDK1.8之后则将永生代彻底移除,取而代之的是直接内存中的元空间。

2.4 方法区

​ 方法区又叫非堆,里面存放了类信息、常量、静态变量等信息,方法区也被称为永久代,其实方法区JVM虚拟机的规范,而永久代是HotSpot关于方法区的实现。

​ 因为方法区的内存大小是固定大小的,在JDK1.8之后移除了方法区,添加了元空间,元空间的内存大小可以通过参数设置。

2.5 运行时常量池

在这里插入图片描述

2.6 直接内存

直接内存并不在虚拟机内,JDK1.4后加入了NIO使得可以使用native函数库直接分配堆外内存,避免了Java堆和Native堆之间来回复制数据。

二. HotSpot虚拟机

1. 对象的创建(五步)

1.1 类加载检查

虚拟机遇到new指令时,会到常量池中查找是否有该类对应的符号引用,然后再检查该类是否已经被加载过,如果没有加载过,那就必须执行相应的类加载过程。

1.2 分配内存

类加载完后,需要给创建的对象分配内存空间,根据GC收集器管理内存的方式可以分为两种分配方式,指针碰撞空闲列表

指针碰撞:适用堆内存规整的情况,即GC算法是标记-整理复制算法的情况。

​ 因为内存是规则的所以,直接移动边界指针就可以分配内存。

空闲列表:对于内存不规整的的情况,JVM会维护一张内存表,表内记录了内存的使用情况,分配内存时只需要找 到一个足够大的内存块就行。

因为对象创建是非常频繁的,所以就必须保证线程安全,JVM保证对象创建线程安全有两种方式:

CAS+失败重试:CAS是乐观锁的一种实现方式,所谓乐观锁就是不加锁假设没有冲突的去执行操作,如果冲突失 败就重试,直到成功为止。这种方式保证了更新操作的原子性。

TLAB:这种方式会为每个线程的Eden区分配一块空间,当创建对象时,会先分配TLAB的内存空间,如果TLAB的内存不足,则再使用CAS的方式进行分配内存。

1.3 初始化零值

初始化零值会给对象的成员变量赋予默认的初始值

1.4 设置对象头

对象头存放了与类和对象相关的信息。

1.5 执行init方法

从JVM看对象已经创建,从程序员角度看对象创建才刚开始,执行init方法按照程序员意愿进行初始化,初始化后对象才真正的创建出来

三. Sting类与常量池

1. String创建的两种方式

1.String s = "abc";
2.String t = new String("abc");

第二句,现在查找常量池中是否存在“abc”,如果不存在则创建,然后再在堆中创建对象。

2.字符串拼接

1.String s1 = "hello";
2.String s2 = "world";
3.String s3 = "hello" + "world";
4.String s4 = s1 + s2;

s3 只会在常量池中产生“helloworld”对象。

而s4 通过引用拼接则会创建一个StringBuilder对象,通过StringBuilder对象的append方法进行字符串的拼接,然后调用toString方法返回一个String对象,也就是说s4 会在堆中产生一个新的对象。

3. String常量池的使用

1.String a = "123";
2.String b = a.intern();

第一句,直接使用双引号声明的String对象会直接存储在常量池中

第二局,String.intern方法是一个Native方法,它的作用是返回常量池中的对象,没有则创建。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值