java对象创建过程
我们作为程序员觉得java创建对象比较简单,只需要new一下就ok,然后用这个对象来操作,不用管垃圾回收等工作。
其实我们用的东西越方便,底层实现的东西就会越多。这就好比开发网站,我们不用框架,纯手写,自己导入java包,
自己写servlet。自己新建bean对象很麻烦。这时候框架出现了。maven帮助我们管理jar包。ssm框架帮我们简化servlet
用controller取而代之。通过注解帮助我们新建对象等。但是我们有了框架之后是不是感觉运行的时候变慢了,就比如
tomcat的启动速度。java也是如此,帮助我们实现对象创建,垃圾回收等工作。还提供给了我们现成的函数来用,所以
java的速度相比于c语言,c++等运行上还是有一定的差异。闲话扯到这里。
到底java对象是怎么分配到内存并且被回收的呢?我们来了解下。
1:当虚拟机碰见new关键字时,会先去常量池查看是否能定位new的这条指令的符号引用。比如Test a=new Test();
会先去看看能否在常量池中找到符号引用,这个符号引用记录了这个类的加载,解析,初始化。如果没有,就会先
执行类的加载过程。
2:类的加载检查确定后,会对新生成的对象分配内存。分配的大小是在类加载的时候就确定好的。为什么对象的大
小会被确定呢?加入我们的类有int,long,integer,string内存。int,long类型是有上限的,jvm直接给你分配那么
大的内存,而integer又可以拆箱为int,大小也是有上限的。string类型是无限制的,但是string储存的是string的地
址。大小确定之后,这时候有两种为对象分配内存的方式:
指针碰撞:有一个指针作为分界点,用过的内存在一边,没用过的内存在另一边。当需要分配内存的时候,需要
移动指针到固定大小的距离即可。这种方式分配内存的方式是线程不安全的。比如线程1的对象a需要分配内存,
线程2的对象b也用到这个指针,这时候就会出错。一种方案是对分配对象内存就行同步处理,虚拟机采用了CAS
和失败重试的方式保证了分配的原子性。另一种是对每个线程都有一个独立的堆内存(TLAB)上篇博客有介绍。
空闲列表:如果已使用的内存和未使用的内存交错着,就无法简单的通过移动指针来分配内存,这时候虚拟机会
有一个列表,记录哪些内存是可用的。然后在列表中划分给实例来使用。当对象实例消亡之后就会收回内存,重新
更新这个列表。
具体使用哪种分配方式由堆的内存是否规整决定的,而内存是否规整又是否gc回收的算法是否有压缩整理决定的。
有压缩整理的算法有Seria,ParNew等算法。
3:jvm完成上述步骤之后会对对象进行一些必要的设置,这个对象是那个类的实例,如何找到类的元数据信息,
对象的哈希码等都存在对象的信息头中。
4:执行<init>方法,对对象进行一定的初始化过程。使这个对象成为能够被我们所用的对象。