今日复习内容:java的运行时的内存区域、java内存模型、java类的加载机制
主要分为以下几个部分:
线程共享
线程独享
常见错误:
OutOfMameryError StackOverFlowError
调用的本机的方法,比如C的方法
线程切换的时候,记录当前线程执行的位置
用于存放对象实例,是虚拟机管理的最大的内存,是GC管理的主要区域。从垃圾回收的角度看,堆区域还可以细分,这和不同的JVM实现有关。
没有规定说方法区在哪一个位置,所谓的方法区只是一种规范,不同的JVM实现存放的地址不一样
方法区中主要存放的是,类的元信息,类的静态变量、常量。
在JDK1.8之后,HotSpot方法区的实现
当我们谈论Java的内存细分的时候,线程独享三块内存区域:
因为其因为生命周期和线程同步,所以它们的回收时间都是固定的,线程死亡之后自然就回收了
而堆和方法区回收时间是不确定的,所以讨论内存模型的时候往往都需要讨论内存回收的机制,所以Java的内存模型主要是建立在 堆和方法区上的。
那么内存模型的具体划分应该是:
堆区,虚拟机来分配:
新生代
非堆区,本地内存分配
后面根据这个划分,具体说明不同区域不同内容是如何回收的
主要分为如下几个阶段
加载
.class
文件的字节流,可能来自于jar包、war包、网络等。 产物
1、2中所述有class文件 静态常量池,和运行时常量池 ,还有一个是 字符串常量池 的概念。
字符串常量池也要 全局常量池 :保存的是字符串实例的引用
String s /= new String("1"); s.intern(); String s2 /= "1"; System.out.println(s /== s2); String s3 /= new String("1") + new String("1"); s3.intern(); String s4 /= "11"; System.out.println(s3 /== s4); jdk6 false false jdk7+ false true
String s = new String("1")
常量池生成“1”的引用
所以
String s3 = new String("1") + new String("1")
此时在全局常量池池是没有“11”的,但是在堆中有StringObject的
在调用 s3.intern()
Jdk6:常量池中生成实际对象“11”,返回其地址,这和StringObject的地址不一样,所以返回false
jdk7+:不在创建对象,而是将SringObject对象的地址存入常量池,此时s3指向StringObject,返回true
链接
解析:符号引用转换成直接引用即具体的内存地址
初始化
针对对象的主动引用和被动引用决定是否触发。
主动引用
被动引用 * 初始化类的数组不会初始化类 * 引用父类的静态变量,不会引起子类的初始化 * 引用类的常量不会,final static修饰的变量,因为在准备阶段就完成了解析 初始化的顺序 父类 --- > 子类 静态 ----> 普通 ---> 构造函数
类加载器
主要有三类
双亲委派模式
tomcat为什么要自己实现类加载器
结构构造
首先容器和应用之间由共用的
应用共有
每一个jsp文件都有jsp类加载器
打破双亲委派模式:webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。
如果上层想加载下层中的类,使用线程上下文加载器。