1. 概述
橙色区域:所有线程共享,存在GC(垃圾回收)
灰色区域:线程私有
2. 类加载器
什么是沙箱?
Java安全模型的核心就是Java沙箱(sandbox),沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括——CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。
3. 本地方法栈
native
关键字主要用于方法上
- 一个native方法就是一个Java调用非Java代码的接口。一个native方法是指该方法的实现由非Java语言实现,比如用C或C++实现。
- 在定义一个native方法时,并不提供实现体(比较像定义一个Java Interface),因为其实现体是由非Java语言在外面实现的
4. 程序计数器
5. 方法区
6. 栈
栈管运行,堆管存储
JVM栈中的 栈针 = Java中的方法(函数)
深度调用后,撑爆了栈,是一个错误,不是异常
Exception in thread java.lang.StackOverflowError
java.lang.Object
——java.lang.Throwable
——java.lang.Error
——java.lang.VirtualMachineError
——java.lang.StackOverflowError
7. 堆
1. 堆在物理上分为两部分:新生区+养老区
2. 幸存者0区,别名S0区 (from区)
幸存者1区,别名S1区 (to区)
3. from区和 to区是有交换的(非固定的);每次GC后会交换,谁空,谁就是to区
7. 堆参数调优
IDEA中的run栏设置VM Options为:
-Xms1024m -Xmx1024m -XX:+PrintGCDetails
import java.util.Random;
/**
* -Xms1024m -Xmx1024m -XX:+PrintGCDetails
堆初始化内存,堆最大内存 打印出堆GC回收信息
*/
public class HeapSpaceTest {
public static void main(String[] args) {
/**
* 输出: MAX_MEMERY = 1808269312(字节)1724.5MB
TOTAL_MEMERY = 122683392(字节)117.0MB
* @param args
*/
// long maxMemory = Runtime.getRuntime().maxMemory();//返回Java虚拟机试图使用的最大内存量
// long totalMemory = Runtime.getRuntime().totalMemory();//返回当前使用的java虚拟机的内存总量
// System.out.println("MAX_MEMERY = " + maxMemory +"(字节)" + (maxMemory/(double)1024/1024) + "MB");
// System.out.println("TOTAL_MEMERY = " + totalMemory +"(字节)" + (totalMemory/(double)1024/1024) + "MB");
//-Xms8m -Xmx8m -XX:+PrintGCDetails
String str = "www.shiye";
while(true) {
str += str + new Random().nextInt(9999);
}
/**
* 结果: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
*/
}
}
package com.shi.jvm;
public class HeapTest {
public static void main(String[] args) {
/**
* 堆内存异常
* 输出结果:当前最大可用内存多少M : 1724
* Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
* at com.shi.jvm.HeapTest.main(HeapTest.java:8)
*/
System.out.println("当前最大可用内存多少M : "+Runtime.getRuntime().maxMemory()/1024/1024);
//创建一个大对象
byte[] b = new byte[1*1024*1024*1725];
System.out.println("大对象创建成功");
}
}
8. GC(分代收集算法)
因为Old区占Heap的2/3,比Young区更大,所以扫描更慢,即Full GC更慢
①引用计数算法
②复制算法:年轻代中使用的是Minor GC,这种GC算法采用的是复制算法
复制算法过程:
- GC开始的时候,对象之存在于Eden区和名为From的Survivor区,Survivor区中的To区是空的。
- 紧接着进行GC,Eden区中所有存活的对象都会被复制到To区;From区中年龄达到阈值的对象会被移动到老年区,未达到阈值的对象会被复制到To区。
- 经过此次GC,Eden区和From区都被清空,From区和To区交换身份,总能保证To区为空。
- 当To区被填满,所有对象移动到老年区中。
③标记清除(Mark-Sweep)算法
- 老年代一般是由标记清除或标记清除与标记压缩的混合实现
- 优点:不需要额外空间
- 缺点:两次扫描,耗时严重;会产生内存碎片(内存不连续)
若可使用的内存被耗尽时,GC线程就会被触发并将程序暂停,随后将
要回收的对象标记一遍,最终统一回收这些对象,完成标记清理工作接下来便让应用程序恢复运行。
④标记压缩(Mark-Compact)算法
- 优点:不产生内存碎片
- 缺点:需要移动对象的成本(耗时)
9. JMM(Java内存模型)
JMM (Java内存模型Java Memory Model,简称JMM) 本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。I
①JMM特征:
- 原子性
- 可见性
- 有序性
②volatile
是Java虚拟机提供的轻量级的同步机制
- 保证可见性
- 不保证原子性
- 禁止指令重排
由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到的线程自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成,其简要访问过程如下图:
public class JMM {
public static void main(String[] args) {
MyNumber myNumber = new MyNumber();
new Thread(()->{
System.out.println("Come In!!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myNumber.change();
System.out.println(Thread.currentThread().getName()+":"+myNumber.number);
},"AA").start();
while (myNumber.number==10){
}
System.out.println(Thread.currentThread().getName()+":"+myNumber.number);
}
}
class MyNumber{
volatile int number=10;
public void change(){
number=1250;
}
}