jvm 知识点摘要

1.jvm家族成员:sun-hotspot,ibm-J9,bea-jrockit

2.jdk8的新增功能:

  •     对lambda表达式的支持,让Java语言拥有了流畅的函数式表达能力
  •     内置nashorn javascript引擎,增强jvm对javascript的运行能力
  •     新的时间、日期API
  •    彻底移除永久代(用本地内存的元空间meta-space代替永久代实现方法区)
  • Java Mission Control监控工具

3.句柄:用来记载数据地址的变更,标识对象或者项目的标识符由来(一种虚拟地址)

4.hotspot诸多特点:

  • 热代码探测:把反复执行的代码编译成机器码,下次执行就可以直接执行,不用出发解释(和执行计数器配合使用)
  • 解释器:一种计算机程序,它直接执行编程语言代码,不会将代码预编译为机器码
  • 编译器:将高级语言写的程序转变为机器语言
  • JIT:即时编译。对于经常使用的字节码,会把该代码的整个方法为单位,一次性将整个方法的字节码编译为本地字节码
  • OSR:栈上替换编译。运行时替换正在运行的函数、方法的栈帧技术

二.内存区域及内存溢出异常

1.运行时数据区域

 

 
运行时数据区域
方法区(Method area)虚拟机栈(vm stack)
本地方法栈(native stack)
堆(heap)程序计数器(pcr)

                                                                                                               注:蓝色背景表示线程共享区域

  • 虚拟机栈:每个方法的执行,jvm都会创建一个栈帧用于存储局部变量,操作数栈,动态连接,方法出口等信息。
  • 堆:Java对象和数组都在堆上分配。垃圾回收器管理的内存区域.通过xms(启动获取内存)和xmx(最大可扩展内存)来设置扩展实现。
  • 方法区:存放常量池、静态变量

2.对象的创建:

  1.   类加载
  2.   查询对应的类信息
  3. 分配内存空间
分配方式java堆是否规整(果)gc是否带有空间压缩功能(因)
指针碰撞
空闲列表不带

 

3.cas:比较再交换,乐观锁。区别于Synchronized悲观锁。java中的AutomicXX类底层均是采用cas。

内存值v完全相等才会将B赋值给v
预期值A
新值B 

 

4.分配内存的线程安全问题解决方案:

  1.   cas+失败重试保证原子性
  2.  使用本地缓冲区(thread local allocation buffer ,tlab):每个线程拥有自己的缓冲区,只有本地缓冲区用完了才会同步锁定。

5.对象的内存布局:

对象在堆内存的存储布局:对象头header,对象体body和对齐填充

位置作用
对象头headermark word:存储自身的运行时数据。如线程id,hashcode,锁状态,gc分代年龄等
类型指针:指向它的类型元数据的指针
对象体body存放实列数据
对齐填充(4k对齐) 

 

6.内存泄漏(memory leak):GC无法回收对象,对象应当被回收

  内存溢出(memory overlow):对象都是有用的

三.垃圾收集器和内存分配策略

1.哪些内存需要回收?

 线程独享的区域生命周期和线程一样。方法或者线程结束时区域自动回收。

编译器即可确定内存大小的不用动态回收。Java堆和方法区只有在运行期我们才能知道程序究竟会创建哪些对象。

2 对象是否已死亡?

  • 引用计数法:对象互相引用特例
  • 可达性分析:

GC ROOTS根对象:通俗讲就是一组存活的元素,比如常量引用对象,类静态属性引用的对象等

3. 引用类型

    存在的意义:这个世界并不是非黑即白,同样,Java对象也不是只有‘被引用’和‘未被引用’两种状态。可以是内存足够时存活,内存不足时抛弃。

    实现:Java.lang.ref包下。分为强引用(我们平常使用的都是这种),软引用,弱引用,虚引用四种。

  • 强引用:只要强引用存在,对象就永远不会被回收
  • 软引用:还有用但非必须。利用软引用实现告诉缓存组件  weakhashmap
  • 弱引用:只能生存到下一次GC
  • 虚引用:不影响对象的生存时间,唯一目的时为了对象被回收时能接收到一个系统信息

          

4.jvm如何判断一个对象是否死亡?过程如何?

  1. 可达性分析,不可达的话第一次标记
  2. 筛选是否有必要执行finalize()【任何一个对象的finalize方法都只会被系统自动调用一次】
  3. 有必要---》放入 F-Queue队列中-----》jvm线程执行,但不保证结束
  4. 自救,再次和任一对象建立连接
  5. 未自救成功,第二次标记-----》等待死亡的降临

5.回收方法区:主要针对常量池和对类型的卸载

6.垃圾收集算法:

  1. 分代收集理论
    建立基础弱分代假说:大部分对象都是朝生夕死 
    强分代假说:熬过越多次GC的对象越难以消亡 
    具体实现Java堆划分出不同区域后,每次回收区域不一样,各区域算法也不同minor gc
    marjor gc
    full gc
    跨代引用

    新生代上建立1个记忆集数据结构。记录老年代中存在跨代引用的部分。minorgc 时将这个内存里的对象加入到GcROOTS中

     
    算法类型标记-清除算法:标记过程就是判断对象是否死亡的过程

    缺点:执行效率不稳定

    产生大量的空间碎片

    标记-复制算法(半区复制):将空间分成多块,每次GC复制活的对象到另一块,然后清空整个区域。新生代多用这种算法缺点:空间浪费,要有分配担保
    标记-整理算法:标记-》存活对象移到一端-》以边界清理。老年代多使用此算法 

    新生代回收机制(标记-复制)为何是1个eden,2个survior?

    From survior,To survior。两个区域轮流充当空闲区域

2.伪共享:多个线程操作的不同对象处于同一个缓存行cacheline,就会彼此影响导致下性能下降。(原因:MESI缓存一致性和RFO协议)

3.cpu缓存机制:(volatile能够实现可见性的原因就是MESI和cpu缓存机制)

背景为解决cpu处理速度远高于内存读写速度,新增cpu高速缓存 
级别L1:离得距离最近,速度最快,空间最小只能别单个cpu单独使用
L2
L3:离的最远,速度最慢,空间最大一个卡槽上的所有cpu共同使用

 

四.虚拟机加载机制

1.类的生命周期:

加载通过全限定名获取二进制字节流
将静态存储结构转化为方法区的运行时数据结构
在内存中生成java.lang.class对象
连接验证保证class文件符合规范,不会危害虚拟机的安全
准备为静态变量分配内存并设置默认初始值(被final修饰的静态变量特例,会在准备阶段就直接赋值指定的值)
解析将常量池内的符号引用(用一组符号字面量表示引用的对象)替换为直接引用(句柄、指针)
初始化 
使用 
卸载 

2.常量池优化机制:

  1. 如果池中有像创建的对象,则直接将指针赋值给该变量
  2. 如果是几个字符组成的字符串,变成字符串常量时也要遵循上一条规则
  3. 常量优化只针对常量,有变量的不可以

3.双亲委派类加载结构:通过组合模式复用父类加载器的功能

 

启动类加载器bootstrap class loaderrt.jar/tool.jar
扩展类加载器extension class loaderjre/lib/ext
应用程序类加载器 appplication class loaderclasspath

五.程序编译与代码优化

1.语法糖:对语言的编译和功能没有影响的一种语法,例如Java中的泛型

2.拆装箱陷阱:Java中的包装类型底层使用了享元模式,预先准备了一定范围的数值。例如Integer的范围在[-128,127]不用新建,超出范围需要新建对象。

此外,.equals()不处理数据转型的关系

 

六.Java内存模型与线程

1.TPS:每秒事务处理数,代表1秒内服务端能响应的请求总数

2.内存模型:

preview

主要目的:定义程序中各种变量的访问规则,即关注在虚拟机中把变量值存储到内存和从内存中取出变量值。

所有的变量都存储在主内存,每个线程有自己的工作内存,里面保存了该线程使用的变量主内存副本,线程对变量的所有操作都必须在工作内存里进行,不能直接读写主内存数据。

3.volatile :

语义保证多线程情况下变量值的可见性机器码lock会将本处理器的缓存写入内存,引起其他处理器的缓存无效化,重新读取内存数据
禁止指令重排序lock禁止将其后面的指令重排序到其前面去,相当于内存屏障的作用
例子dcl(double check lock)懒汉式单例模式

 

4.java内存模型概述:

线程安全的实质如何保证
原子性默认基本数据类型的访问,读写都具有原子性
synchronized
可见性synchronized
volatile
final
有序性volatile
synchronized

 

5.Java先行发生原则:

程序次序规则单个线程内表现为串行
管程锁定规则同一个锁必定是先释放才能被获取
volatile变量规则 
线程启动规则 
线程终止规则 
线程中断规则 
对象终结规则 
传递性 

 

6.Java与线程(cpu资源调度的最基本单位):

线程的实现内核线程(1:1)内核是操作系统的最基本部分。为众多的应用提供对计算机硬件的安全访问的一部分软件
用户线程(1:n) 
用户线程+轻量级进程(n:m) 
Java线程调度协同式线程自己决定执行时间
抢占式(java)系统控制(java添加了10各级别的线程优先级)
Java线程状态new  
runningstart()可能正在运行,也可能在等待分配时间片
waitingsleep():不释放锁,waiting():释放锁,notify()无限期等待,需要其他线程的显式唤醒
time_waiting一定时间后系统自动唤醒
blockedsynchronized等待获取一个排他锁
terminaterun()结束 

 7.线程安全

按照由强到弱,java中各种操作共享数据可分为不可变final+基本数据类型
非基本数据类型的对象状态不能被改变。例如String的任何方法都不会改变它原来的值
绝对安全基本不存在,代价很大
相对安全(我们平常说的线程安全)单次的操作是安全的,多线程时可能需要在调用端使用同步手段保证安全,例如vector
线程兼容对象本身不是线程安全的,需要在调用端使用同步手段保证安全,例如arraylist
线程对立不管采用什么措施,都不能保证并发安全,应尽量避免。例如suspend()和resume()

 

8.如何保证线程安全

互斥--》同步悲观锁synchronized 可重入锁
reentrantlock(lock必须在finally块中释放,否则出现异常可能导致永远不会释放锁)等待可中断
公平锁(性能较差)
所绑定多个条件(condition)
非阻塞同步乐观锁cas无锁编程存在ABA漏洞
无同步方案可重入代码  

 

4.锁优化

偏向锁无竞争,只有一个线程,不需要同步。如果程序中大部分锁都存在竞争,则应该关闭偏向锁。(偏向锁的threadid占用了原本hash码的空间,hash码不应该变化,所以计算过hash的对象无法再进入偏向锁状态)
轻量级锁无竞争,cpu自旋获取锁,不阻塞
重量级锁阻塞

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值