1.进程是操作系统分配资源的最小单元
2.线程是操作系统完成调度的最小单元
3.jdk=jre(包含jvm(可以把.class文件的字节码转成各种操作系统能够识别的机器码))+各种工具包(javac 编译 java运行 javap反编译)
jre=jvm+基础类库
4.jvm上可以运行多种语言,只要满足字节码的规范
5.java的内存区域 {
1.7 线程私有的有,程序计数器,虚拟机栈,本地方法栈
线程共享的有堆,和方法区,这时的方法区也叫永久代在堆内
}
1.8线程私有的有程序计数器,虚拟机栈,本地方法栈
线程共享的有堆和方法区,也叫元空间在内存中
虚拟机栈:存储java方法的数据指令返回地址等
本地方法栈:和虚拟机栈相似服务的是native方法
程序计数器:每开一个线程就会开一个程序计数器,记录着当前线程正在执行的字节码指令的行号或者说地址(比如线程执行到第十三行,被调度,下次回来继续运行的时候就知道是第十三行)
方法区:存放一些静态的可以被线程共享的东西,存放常量池、类的信息
堆:几乎所有的对象都是在堆中存放
jvm内存里面会发生内存溢出的区域(oom)除了程序计数器都会
1.虚拟机栈:如果是递归调用,不断的向栈里面压入栈帧,会导致溢出
2.堆:创建的类多了,堆不够使用,垃圾回收之后还是不够使用
3.方法区:创建的类过多,类的信息过多 meta space
4.本机直接内存(堆外内存),bytebuffer可以申请这一块的内存,如果超过就会溢出
6.jvm在创建对象时采用了哪些安全机制
指的是在分配内存时出现的安全问题
方法一用cas的方法乐观锁 加锁完成
实际上是本地线程分配缓冲,每个线程分配一个缓冲区,在缓冲区上分配内存。就不存在竞争情况
填充是要保持8字节的大小
7.为什么不用finalize方法
第一次标记垃圾回收会标记没有在引用链上的对象,第二次标记回收会把重写了finalize方法的对象解救出来。但finalize方法的优先级很低,gc()之后要等待一些时间才能解救出来,不然来不及解救。
而且finalize方法只能执行一次 第二次垃圾回收就不会被解救
8.判断对象是否存活
引用计数法,被引用就加一,为0 的就是没有引用的,就可以被回收,但是会有循环引用的问题科可达性分析,与根没有关系的就是可以回收的
8.标记整理算法:是可达性分析之后把可达的对象整理好之后在对象的末尾到最后做统一的正路
9.为什么扩容新生代能提高gc的效率
扩容新生代 那么每次要等到新生代满了才会回收垃圾 这样的话时间更长,能让更多的对象变成垃圾,减少复制的次数。
10.cms
初始标记
gcroots:静态变量,常量,局部变量
这一步进行暂停 stop the world
并发标记
就是可达性分析下 标记除gcroots在引用链上的其他对象,但是不停止其他的线程,并发进行,因为标记的时间长。
重新标记
在并发标记的过程中,可能出现对象有变动的情况,那么就stop the world 重新标记
并发清理
为什么可以并发,没有标记的是没有用的,先清理,标记的继续运行
==========================cms问题=====================
CPU要多,CPU少在并发的时候就吃亏
会产生浮动垃圾,在并发清理的过程中,有些被标记的变成了垃圾,就产生了浮动垃圾,没有被清除,所以内存的利用率不是100% 总有浮动垃圾占着。
会产生内存碎片,会退化成单线程 标记整理 但是效率非常低
==================守护线程和用户线程========================
守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,连jvm都停止运行了,守护线程当然也就停止执行了。
守护线程 thread。setdeamon(true),其他所有的线程都结束了他才会结束
用户线程,main结束了他也不会结束,要一直执行完
===================上下文切换================
多个线程,第一个线程时间片用完了,CPU要记录他的信息,CPU接第二个线程,要恢复第二个线程的一些信息,这些信息叫做上下文,完成这个操作叫上下文切换。
==============================executor和executors的区别============
executor是一个接口 他下面就有 threadpoolexecutor这个类来创建线程池
executors是一个工具类帮忙创建
==========================cas=================
1.会产生第一个问题如果一直循环等待开销比较大
2.第二个问题共享一个变量,有局限性
3.ABA 问题 如果实时状态是1线程1把状态改成了2,之后改成更1没有问题
但是如果实时状态是一个应用类型 如果我们的compare比较是否为空的话就会出现脏读的情况
例如原来的object 不为空,之后线程1改为空,之后又改为非空但是里面的内容改变了,但是线程2compare的时候发现是非空,执行资源对象的时候出现脏读