1.JVM虚拟机读书总结

JVM学习笔记

1.Java内存区域与内存溢出异常

java内存区域分为公用堆、公用方法区、虚拟机栈、本地方法栈、程序技术器 如图所示1.1
在这里插入图片描述

1.1 程序计数器

相当于一个程序指针,标记当前线程执行的位置。Java是多线程的,所以每个线程要来回切换,所以每个线程都有一个独立的程序计数器

1.2 虚拟机栈

虚拟机栈的生命周期与线程相同,用于存储局部变量表,操作数栈、动态链接、方法出口。当谈到栈时多数人会指的是局部变量表,局部变量表存储基本数据类型、引用数据类型地址,以局部变量槽的形式存储。数据在局部变量表中占用的大小不同,long和double通常占用两个变量槽,其他数据占用一个。局部变量表要分配多少内存在编译期间就已经确定了,进入一个方法,栈已经分配好了局部变量表的大小,运行时不改变,栈是私有的,随线程销毁而销毁,即方法执行结束,局部变量销毁。当线程请求栈深度大于虚拟机允许的深度则StackOverflowError异常,栈溢出,若虚拟机支持栈扩展可能会内存溢出异常OutOfMemoryError.
在这里插入图片描述

1.3 本地方法栈

本地方法栈与虚拟栈类型,虚拟机栈是为虚拟机执行class方法的服务,本地方法栈是虚拟机使用本地方法的服务。常用的HotSpot虚拟机将虚拟机栈和本地方法栈合二为一。

1.4 Java堆

Java堆是内存管理中最大一块,用于存储对象数据,对空间被所有线程共享,Java堆是垃圾回收的管理区域,又称GC堆,Xmx Xms可以设置对空间的大小

1.5 Java方法区

方法区是共享区域,存储类加载、静态变量、常量等数据。方法区并不是一直都有的,在JDK1.8中将永久代的数据,转入了元空间中,即在现在的发展方法区的内容是可以被回收的,只不过是回收条件比较苛刻,如类型卸载。

1.6 Java方法区运行时常量池

用于存放运行时常量,并不只是Class文件加载时的常量能进入常量池。Java的常量可以在运行时产生

1.7 直接内存

在jdk1.4时,加入了一种NIO技术,可以使本地函数库直接分配到堆外内存,然后通过存在堆里的DirectByteBuffer对象引用这块内存,这样就不用在Java堆和Native堆来回复制了,也就是说,为提高效率,另画出一块内存,然后这块内存的内容常用到,调用时直接从这里面找,不用调用堆。当我们设置Xmx最大虚拟机内存参数时,应考虑到直接内存的因素。不然换分的内存区域都大于实际的内存,堆扩展时容易产生内存溢出。

1.8 对象的创建

java new一个对象先判断方法区常量池中有无对应的常量、找到一个类符号引用,检查这个符号代表的类是否被加载过,解析和初始化过,如果没有执行类加载。在堆中给类分配空间时有两种一种 是指针碰撞型,中间有个界限,一边是空闲的,一边是用过的。分配时调整空闲指针即可。一种是空闲列表型,记录那块内存是空闲的,基于回收算法理论上只能用这种分配内存。内存分配完分配的内存都初始化为0值,接下来设置对象头,这个对象属于哪类对象,对象的GC分代年龄等,然后才到了构造函数。
在这里插入图片描述

1.9 访问对象的两种方式

在这里插入图片描述
内存回收,就要移动对象位置,移动位置时,句柄方式只改句柄地址,不改变栈地址,相对稳定。但是效率慢,直接指针改变栈地址,效率快(HotSpot虚拟机利用这种)

1.10 虚拟机结构图

在这里插入图片描述
jdk1.8将常量池,放到了堆中,取消了永久代,将方法区放入元空间,并定义了3个参数动态改变元空间大小,当方法区要溢出时,会利用垃圾回收卸载类型。
在这里插入图片描述
这段代码在jdk1.6全是 false,1.7第一个是true,第二个是false
在jdk1.6时常量池还在方法区,所以调用intern函数获取的方法区,而str1定义在堆中
在jdk1.7后常量池在堆中,所以第一个是输出true,计算机软件字符在常量池未定义,所以他们都是堆中常量区字符串的地址。第二个java字符输出false是因为,StringBilder函数调用时,已经把java字符放入了常量池,此时str2.intern返回的是常量池地址,str2是堆中地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值