3个classLoader:启动加载器Bootstrap(C++)
,扩展加载器Extension(Java)
,应用程序类加载器AppClassLoader, 分别是祖父孙, 他们都是抽象类,需要被继承。还有用户自定义加载器Java.lang.ClassLoader
的子类,用户可以定制类的加载方式, 通过继承ClassLoader类
new Object().getClass().getClassLoader()
为Bootstrap,是Java祖宗级,在java里输出为nullnew MyObject().getClass().getClassLoader()
,即自己new的类,它的加载器是AppClassLoader , 父加载器为Extensionnew Thread().start()
只是新建完成到就绪状态,是否被运行决定于底层操作系统和CPU的调度方法区 f = new 永久代
java8之后:方法区 f = new 元空间
类的实例方法和实例对象存在堆内存中,和方法区无关
如果执行的是Native方法,那这个计数器为空
栈管运行,堆管存储。在Java中,程序 = 框架 + 业务逻辑
线程私有,不存在GC问题,8中基本类型变量+对象的引用变量+实例方法都是在函数的栈内存中分配
Java方法被压到栈中,叫做栈帧, main方法最先被压栈,栈帧是内存区,是有关方法和运行期数据的数据集
栈帧中主要保存三类数据:(栈中的数据都是以栈帧的格式存在,在JVM栈里方法叫栈帧,在JVM外叫方法)
栈运行原理:
栈溢出错误SOF:StackOverflowError
A a = new A();
等号左边是引用,在栈里,等号右边是实例对象,在堆里;
栈、堆和方法区的交互关系:
类元数据
(Class模板)的地址,reference存储对象的地址1.新生代(PSYoungGen):
1.伊甸区(Eden Space): new对象存在该区,GC(也叫 YGC 或轻GC 或 MinorGC)在该区产生;在内存超过阈值时开启GC之后,除了正被引用的对象和静态变量被移动到S0区,未存活的对象 被 JVM清除
普通MinorGC:复制(GC复制算法复制到To区) → 清空(Eden和from全部清空) → 互换(S0和S1互换,谁空谁是to区)
2.幸存者0区(Survivor 0 Space, 也叫S0 或 from区):每次GC也会进行复制清空互换的过程
3.幸存者1区(Survivor 1 Space,也叫S1 或 to区):与S0区机制相同
2.老年代(养老区ParOldGen):当对象超过内存阈值后,开启Full GC(也叫FGC或重GC或全局GCMajorGC),多次FGC后无法再腾出空间,将抛出OOM(OutOfMemoryError
)堆内存溢出错误,Major GC比 Minor GC慢上十倍左右,每次Major GC经常(不是绝对)伴随一次Minor GC
3.元空间Metaspace(Java7叫永久代或持久代):
Runtime.getRuntime().totalMemory;
// 获取最大堆内存, Runtime.getRuntime()为Runtime Data Area对象1.引用计数法(了解即可):每次GC一个对象被引用就+1,没被引用-1,当为0时就清除。System.gc 不会立刻开启GC
2.复制算法(Copying):年轻代中使用的Minor GC采用的主要是复制算法
3.标记清除:老年代一般是由标记清除或者标记清除与标记整理的混合实现
是什么:先扫描并标记要回收的对象,接着再扫描一次,然后统一回收这些标记的对象
优缺点:优点是不需要额外空间,缺点是两次扫描耗时严重,会产生内存碎片
4.标记压缩(标记整理):
是什么:相当于标记清除,加上移动对象使内存碎片清除
标记清除压缩:标记清除和标记压缩的结合,不同的是:进行多次GC后才压缩,不算入四大算法
没有最好的算法,只有根据每一代GC的特性来采用对应的算法,因此叫分代收集算法
JVM是一种抽象概念,描述一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段 、静态字段和守城数组对象的元素)的访问方式
volatile是jVM提供的轻量级同步机制
1.可见性:就是个通知机制,一个线程对共享变量的修改,能及时的被其他线程看到
2.原子性:操作不可拆分,要么全成功,要么就不做
3.有序性:如果在本线程内观察,所有操作都是有序的
JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(也叫栈空间),工作内存是每个线程的私有数据区域
JMM规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作必须在工作内存中进行,首先要将变量从主内存拷贝到自己的工作内存空间,再对变量进行操作,完成后再将变量写回主内存 。不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成
一般面试提问:面向对象和高级语法、Java集合类、Java多线程、JUC 和高并发、Java IO和 NIO
获取多线程的4种方法:
1.继承Thread类,重写run方法(其实Thread类本身也实现了Runnable接口)
2.实现Runnable接口,重写run方法
3.实现Callable接口,重写call方法(有返回值)
4.使用线程池(有返回值):通过Executors提供四种线程池
进程:
线程:
笔试:一般一个进程包含多个线程,线程可以利用进程所拥有的资源,在引入线程的操作系统中,把线程作为独立运行和独立调度的基本单位
面试:线程是进程的组成部分,一般一个进程包含多个线程,它代表了一条顺序的执行流。
并发:在同一实体上的两个或多个使事件在同一时间段内发生
并行:在不同实体上的两个或多个事件在同一时刻发生
高内聚:类与类、对象与对象、模块与模块之间高度地聚集和关联
低耦合:AB两个对象可以进行数据共享,但是AB两个对象又各自 独立
在高内聚低耦合的前提下,线程(thread.start())操作(对外暴露的调用方法)资源类(操作的对象):
Thread.currentThread().getName()
获取当前线程名
Thread(Runnable target, String name)
// target:Runnable接口的run() 方法的实现, name:线程名
手机扫一扫
移动阅读更方便
你可能感兴趣的文章