感觉要妥妥分享一波干货知识
new一个对象过程中发生了什么???
Java在new一个对象,会先查看对象所属的类是否被加载到内存,如果没有的话,先通过类的全限定名来进行加载。加载并初始化类完成后,在进行对象的创建工作。
总而言之就是俩个过程:加载初始化类和创建对象。
双亲委派模型
类加载器收到加载请求,自己不会进行加载,把这个请求委托给父类,以此类推。只有当父类反馈自己无法加载,子加载器才会尝试加载。
好处:可以有效确保一个类的全局唯一性,当程序出现多个限定名相同的类时,类加载器在执行加载时,始终只会加载其中的一类。
1.加载
2.验证(语义验证、操作验证)
3.准备(为类中所有静态变量分配空间)
4.解析
5.初始化(先父后子)(静态变量赋值,执行static代码块)
创建对象
1.在堆区分配对象需要的内存
分配内存包括子类和父类的实例变量
2.对所有实例变量赋默认值
方法区内对实例变量定义拷贝一份到堆区,赋默认值
3.执行实例初始化代码
执行顺序:先初始化父类再初始化子类
先执行代码在执行构造方法
4.如果有类似与
child c=new child()
形式的c引用的话,在栈区定义child 类型引用变量c,然后将堆区对象的地址赋值给它。
堆和栈
栈:
管程序如何运行;程序如何执行;如何处理数据
主管Java程序的运行,它保存方法的局部变量,部分中间的结果,并参与方法的调用和返回值,以栈帧的格式为基本单位进行存储
堆:
管理数据的存储
虚拟机内存与本地内存的区别
Java虚拟机在执行时会把管理的内存分配成不同的区域,这些区域被称为虚拟机内存,同时对于虚拟机没有直接管理的物理内存,也有一定利用,这些被利用却不再虚拟机内存数据区的内存,称为本地内存
JVM内存
受虚拟机内存大小的参数控制,当大小超过参数设置的大小时,就会报OOM
本地内存不受虚拟机内存参数的限制,只受物理内存容量的限制
虽然不受参数的限制,但是如果内存的占用超出物理内存的大小,同样也会报OOM
虚拟机栈JVM stacks
每个栈帧包含如下内容:
局部变量表
局部变量表中存储着方法里的java基本数据类型(byte,short,int,long,float,double,char,boolean)以及对象的引用
操作数栈
动态连接
方法返回地址
虚拟机异常
Stack OverFlowError:线程请求的栈深度大于虚拟机所规定的栈深度。栈溢出
Out OfMemoryError:虚拟机的栈容量可以动态扩展,那么当虚拟机栈申请不到内存时会抛出。OOM内存溢出
Java堆
java堆是JVM内存中最大一块。由于所有线程共享,是由来及收集器管理的内存区域,主要存放对象实例。由于java虚拟机的发展,堆中也多了许多东西,现主要有:
对象实例
类初始化生成的对象
基本数据类型的数组也是对象实例
字符串常量
字符串常量池原本存放与方法区,jdk 7开始放置于堆中
字符串常量池存储着的是String对象的直接引用,而不是直接存放对象,是一张String table
静态变量
静态变量有static修饰的变量,jdk 7时以方法区迁移至堆中
线程分配缓冲区
线程私有,但是不影响java堆的共性
增加线程分配缓冲区是为了提升对象分配时的效率
成员变量、局部变量、类变量分别存储在内存什么地方?
类变量
是用static修饰符修饰,定义在方法外的变量。随着java进程产生和销毁
在java 8之前把静态变量存放于方法区,在java 8时存放在堆区
成员变量
是定义在类中,但是,没有static修饰符修饰的变量随着类的实例产生和销毁,是类实例的一部分
由于实例的一部分,在类初始化时候,从运行时常量池取出直接引用或者值,与初始化的对象一起放入堆中
局部变量
局部变量时定义在类中方法中的变量
在所有方法被调用时放入虚拟机栈的栈帧中,方法执行结束后从虚拟机找出弹出。所以存放在虚拟机栈中。