好久没有更新博客了 甚是怀念
网上看了很多资料都是对于两者概念比较模糊
首先关于JVM启动流程
*
接下来是JVM内存结构,是结构并不是内存模型
PC寄存器
每个线程拥有一个PC寄存器
在线程创建时 创建H
指向下一条指令的地址
执行本地方法时,PC的值为undefined
方法区
保存装载的类信息
类型的常量池
字段,方法信息
方法字节码
通常和永久区(Perm)关联在一起
但是基于JDK改动:
JDK6时,String等常量信息置于方法
JDK7时,已经移动到了堆
Java堆
和程序开发密切相关
应用系统对象都保存在Java堆中
所有线程共享Java堆
对分代GC来说,堆也是分代的
Java栈
线程私有
栈由一系列帧组成(因此Java栈也叫做帧栈)
帧保存一个方法的局部变量、操作数栈、常量池指针
每一次方法调用创建一个帧,并压栈
**
栈、堆、方法区交互
**
具体代码体现:
public class AppMain
//运行时, jvm 把appmain的信息都放入方法区
{ public static void main(String[] args)
//main 方法本身放入方法区。
{ Sample test1 = new Sample( " 测试1 " );
//test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
Sample test2 = new Sample( " 测试2 " );
test1.printName(); test2.printName(); }
public class Sample
//运行时, jvm 把appmain的信息都放入方法区
{ private name;
//new Sample实例后, name 引用放入栈区里, name 对象放入堆里
public Sample(String name)
{this .name = name; } //print方法本身放入 方法区里。public void printName()
{ System.out.println(name); } }
接下来才是jvm内存模型
接下来是关于线程工作内存以及主内存之间数据交互:
当数据从主内存复制到工作存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作
每一个操作要保证可见性 原子性 有序性
何为原子性:
一旦操作开始,就不会被其他线程所干扰
何为可见性:
当线程A修改共享变量值,线程B能够立刻知道当前修改的共享变量值
何为有序性
是指在单线程环境下,都是按照程序有序的执行,可能有人会问,多线程咋办,所以,这就是接下来的如何保证线程有序性以及线程安全性,这个知识点百度可以解决
涉及到栈 堆 方法区 那么就要涉及到一个OOM(out of Memroy)
堆溢出:集合类中对对象的引用,没有及时处理,导致JVM无法及时回收
**栈溢出:**在需要创建线程的时候,需要为线程分配栈空间,但是栈空间是像操作系统请求的,如果当前操作系统无法满足当前栈空间请求,此刻就会导致内存溢出
***永久区溢出:***永久区溢出现象就是过多对象实体,设置允许回收class
**直接内存溢出:**栈内存,堆内存所占空间过大,导致直接内存不足