第二章 java 内存区域 与内存溢出异常
2.2运行时数据区
方法区,堆==》所有线程共享的数据区
虚拟机栈、本地方法栈、程序计数器===》线程隔离使用的数据区
2.2.1:程序计数器
程序计数器是一块较小的内存,每条线程隔离使用,用于记录线程执行的行号。
多线程执行时轮流获取cpu时间片执行的,当线程恢复执行时,需要接着上一次执行的地址继续执行。
2.2.3 : 虚拟机栈
虚拟机栈是每条线程隔离使用,线程创建时会在栈中分配空间,线程销毁时该空间释放。
栈:先进会出的数据结构。
线程每执行进入一个方法,就会在线程栈中创建一个栈帧,成为当前帧,栈帧用于存储方法的局部变量表,局部变量表中存放着编译期可知的基本数据类型(byte,char,short,int ,long ,double,float,boolean) 和引用对象指针(对象存储在堆中)。为每一个方法创建的帧占用的空间在固定的,因为在编译即可知局部变量个数。
栈异常 StackOverFlowError :原因:线程请求的栈深度(方法调用深度)大于虚拟机允许的深度,与内存无关。
栈异常 OutOfMemoryError: 虚拟机栈空间可以动态扩展,扩展时无法申请到足够的内存
2.2.4 本地方法栈
与虚拟机栈,区别是用来执行native方法。
2.2.5 堆
堆 java 使用的最大的一块内存,用于存储对象实例和数组,所有线程共享。
推中的内存空间收GC回收,为了便于回收又划分为:新生代和老年代。
新生代包括:Eden空间、From Survivor 空间、To Survivor空间。
通过 -Xmx -Xms 指定推的大小。
异常:OutOfMemoryError 当堆中没有空间存储对象实例且堆无法扩展时触发。
2.2.6 方法区
用于存储 类的信息、常量、静态变量,是所有线程共享的一块内存区域。
在hotspot虚拟机中,方法区又叫永久代(持久代)
通过-XX:PermSize -XX:MaxPermSize 指定方法区大小
异常:OutOfMemoryError ,当方法区无法满足内存分配要求时触 发
2.2.6.1 运行时常量池
常量池是方法区的一部分。
Class文件除了有类的版本、字段、方法、接口等描述述信息外,还有常量池,用于存储编译时生
成的各种字面量和符号引用,这部分数据类加载后进入方法区的运行时常量池。
运行期也可以运态的在常量池中添加对象,如 String.intern()方法
String.intern()方法:
方法区内常量池中如果有同等对象直接返回,否则在方法区常量池中创建
String对象并返回。频繁在常量池中创建新字串,可能导至内存溢出。
2.2.7 直接内存
直接内存并不是由虚拟机管理的内存,如DirectByteBuffer ,在一些场景中可以提高性能。
2.3 hotspot虚拟机探秘
2.3.1对象的创建
a)分配空间
堆中为实例分配空间,存在线程安全问题:如A线程创建实例 ,B线程也创建实例,堆中空间有限,
为了避免相同空间分配给不同对象,可采用如下两种方式:
方式一: 分配空间时,使用CAS+重试的机制
方式二: 为每条线程在堆中分配一小块内存区域 ,称为本地线程分配缓冲(TLAB),线程创建的实例,优先在此区域分配空间,避免冲突。 只有TLAB空间被占满时,才使同步锁,顺序的分配堆空间。
是否启用TLAB,使用JVM参数:-XX+/-UseTLAB参数来指定
b) 实例空间分配完成后,将该空间初始化为0.保证了实例在未初始化时就可以使用,值都为0.
(不包括对象头)
c) 初始化对象头,如这个实例是哪个类的,如何找到类的元数据信息,实例的哈希码,GC的分代年龄等信息。
d) 初始化方法被调用(构建器及初始化代码块)
2.3.2 对象实例的内存布局
在堆中,一个实例的内存布局分成三部分:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
对象头数据分为两部分:
a) 对象自身的运行时数据:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID,偏向时间戳。
这部分数据占用空间:32位虚拟机占用32bit。64位虚拟机占用64bit 。
这部分空间,官方称为:Mark Word
b) 元数据类型指针,即指向这个对象实例的类的信息
实例数据:存储程序代码中定义的各种属性的值。包含从父类中继承下来的。
对齐填充:不是必须有的,启占位符的作用,原因:HotSpot虚拟机要求实例的起始地址是8的整数倍。
2.3.3 对象的访问定位
在HotSpot虚拟机中: 栈中 对象引用变量直接指向堆中实例的地址。
第三章 垃圾收集器与内存分配策略
3.2. 对象实例已死的判定算法
堆中对象实例不再使用了,需要释放该实例占用的空间,那么如何判定实例不在使用?
3.2.1 引用计数法
给对象添加一个引用计数器,每当有一个地方引用它:计数器+1,当引用失败时:计数器-1,
任何时刻计数器为0的就是不可再引用对象。
java虚拟机未采用 引用计数法,原因如下:如两个实例相互引用对方,除此之外没有被任何地方引用,实现上这两个对象该被释放空间了,但按引用计数法,它们还是有用的。
3.2.2 可达性分析算法
通过一系列称为“GC roots" 的对象为起始点,从这些节点开始按引用关系搜索,搜索所走过的路径称为引用链,当一个对象到GC roots 没有任何引用链相连,则认为该对象是不可用的。
java 中可以做为GC roots 的对象为:
a):虚拟机栈中本地变量表引用的对象
b):方法区中静态变量引用的对象
c):方法区中常量引用的对象
d):本地方法栈(java 中native方法)中引用的对象
3.2.3 引用类型分类
1)强引用
指程序中普遍存在的类似于 "Object obj = new Object()" 这类引用,只要强引用还存在
垃圾回收器永远不会回收。
2)软引用
描述有用但不是必须的对象。在发生内存溢出之前进行垃圾回收。
3)弱引用
描述非必须的对象,垃圾回收器执行时,不管内存是否足够都 进行回收。
4)虚引用
最弱的一种引用关系,为虚引用关联一个对象实例的唯一目的,是产生垃圾回收时得到一
个系统通知。
3.3 垃圾回收算法
3.3.1 标记-清除算法
1:首先找到GC roots不可达对象,对其标记
2: 对其清理
缺点: 1.标记、清理 :这两个过程的效率不高
2. 产生大量不连续的内存碎片,不利于之后为对象分配空间。
3.3.2 复制算法
为了解决标记清除的效率问题,产生了复制算法。
它将可用内存划分为大小相同的两块,每次只使用其中一块,当这一块用完了就将还存活的
复制到另一块内存上,使用的内存块一次清理掉。这样每次只对一半内存区回收,内存分配也不
考虑内存碎片问题,只是移动堆顶指针,按顺序分配空间。
缺点:内存使用原来的一半。
进一步优化后:
新生代+老年代。
新生代:大块eden空间 + 2个小块相等的Survivor空间。
每次只使用eden 和其中一个Survivor空间,回收时把eden和Survivor上的存活对象复制到
另一个Survior上,最后清理掉Eden 和使用的Survivor.
HotSpot默认 Eden与 一个Survivor 比例为 8:1,也就是新生代中90%的空间可用,只浪费 10%的空间。这些都是基于IBM的研究:98%的对象都是朝生夕死的。
如果另一个Survior上,没有空间存放所有的存活对象,会通过分配担保机制进入老年代。
3.3.3 标记-整理算法
复制算法不适用于老年代,因为该空间内的对象存活比例较大,需要额外的另一块内存空间来复制。
标记-整理算法: 先标记不可达对象(找到存活对象),从老年代的某一端开始,复制所有存活对象,依次分配内存。
3.3.4 分代收集算法
新生代中每次垃圾收集都会有大量对象死去,只有少量存活,那就选择复制算法
老年代中存活率高,没有额外的空间复制,所有使用 标记-清理 或标记-整理算法。
3.4 HotSpot算法
3.5 HotSpot 垃圾回收算法
3.5.1 Serial 收集器
Serial 收集器 是单线程垃圾回收器采用单线程方式,停止所有用户线程进行垃圾回收。
Serial 收集器: 回收新生代采用 复制算法。
Serial old收集器: 回收老年代采用 复制整理算法。
3.5.2 ParNew 收集器
ParNew收集器其实是Serial收集器的多线程版本,采用多线程方式回收垃圾,暂集所有用户线程。
ParNew是新生代的垃圾回收器,默认线程数==CPU数量。 (在cpu<=2的情况下,并不能比Serial收集器快),可以使用能数-XX:ParallelGCThreads指定线程数。
ParNew 收集器采用复制算法。
3.5.3 Parallel Scavenge 收集器
Parallel Scavenge 收集器:回收新生代,采用复制算法,多线程回收,暂停工作线程。
Parallel Scavenge收集器与其它收集器 的不同点:
其它收集器是:尽可能缩短垃圾回收时工作线程的暂停时间。
Parallel Scavenge:提高吞吐量。
吞吐量: cpu运行用户代码的时间/cpu总的消耗时间,即
cpu运行用户代码的时间/cpu运行用户代码时间+垃圾回收时间。如虚拟机总运行时间100分钟,垃圾回收占用1分钟,吞吐量为 99%。
高吞吐量:可以高效率的利用CPU,尽可能的完成程序运算的任务,适合后台计算,不需要太多交互的任务。
其它收集器:适合与用户交互的程,停顿时间越短,良好的响应速度提升用体验。
3.5.4 Serail old收集器
Serail 收集器:回收老年代,采用复制整理算法,单线程回收,暂停工作线程。
3.5.5 Parallel old 收集器
Parallel old 收集器:回收老年代,采用复制整理算法,多线程回收,注重吞吐量,暂停工作线程。
注重吞吐量应用:新生代使用 Parallel Scavenge ,老年代使用Parallel old 收集器。
3.5.6 CMS收集器
CMS收集器:回收老年代,采用标记-清理算法,多线程回收,注重最短停顿时间,与工作线程并发执行。
第十二章 java 内存模型与线程
12.3 java内存模型
java 所有数据存储在主内存中,线程要对某个变量操作时,从主内存中加载数据在工作内存,再由工作内存中读取,再操作,操作完成(赋值)写回工作内存,再从工作内存写回主内存。
工作内存的每条线程私有的,因此多线程同时对于一个变量的操作,可能产生线程安全问题。
多线程间数据交互通过主内存实现的。
工作内存与主内存之间的交互协议:
1.lock (锁定):作用于主内存的变量,它把变量标识为一条线程独占状态
2.unlock(解锁):作用于主内存变量,它把处于锁定状态的变量释放出来,释放后变量才可以被其它线程锁定。 (同一线程程可以对一个变量lock N次,也必须unlock N次)
3.read (读取):作用于主内存变量,它把一个变量的值从主内存传给工作内存,以便之后的load操作使用。
4.load(加载):作用于工作内存变量,它把read操作得到的变量放到工作内存的变量副本中。
5.use(使用):作用于工作内存变量,它把工作内存中的变量传给执行引擎。每当jvm遇到一个需要使用变量值的指令时执行此操作。
6.assign(赋值):作用于工作内存变量,它把从执行引擎接收到的值赋值给工作内存变量。当jvm遇到一个赋值指令时执行此操作。
7.store(存储):作用于工作内存变量,它把工作内存中的变量传给主内存,以便之后的write 操作使用。
8.write(写入):作用于主内存变量,它把store操作的值写入主内存。
锁相关规定:
1.一个变量,同一时刻只允许一线程对其进行lock操作,lock操作可以被同一线程执行多次,多次执行lock后,只有执行相同次数所unlock,变量才会被解锁。
2.对一个变量执行lock操作,会清空工作内存中的值,在执行引擎使用这个变量时,需要重新执行load<---read 操作 加载值。
3.一个变量unlock之前必须,对其执行store-->write写回主内存。
volatile型变量:可见性
1.每次使用volatile变量时,都必须从主内存刷新最新值到工作内存,再操作,用于保证能够看见其它线程对volatile变量的修改值。
2.每次对volatile 变量值修改时,都 必须立刻同步到主内存中,用于保证其它线程能够看到自己对volatile变量的修改值。
3.volatile变量不会被指令重排序优化:即代码执行顺序与程序中的顺序机同。
普通型变量:
1.每次使用变量时,不一定会从主内存刷新最新值,比如当前工作内存中就该变量。
2.每次对变量值修改时,可能不会立刻同步到主内存中。
可见性 :当一个线程修改了一个共享变量值,其它线程能够及时得知这个修改。
1.volatile 保证变量读取时从主内存取值-》工作内存-》执行引擎
赋值时执行引擎--》工作内存-》立即写入主内存。
2.synchronized : 锁定时,清空工作内存此变量的值,从主内存读取,unlock之前,把值写回主内存。
3.不可变对象及final: 变量不可变,对可见性无影响。
禁止指令重排优化:
1.volatail
2.synchronized
synchronized具有: 可见性,原子性(线程串行执行),禁止指令重排优化,
volatail具有:可见性, 可见性,非原子性,禁止指令重排优化
12.4 线程
1.线程调度
分配CPU时间片执行
2.线程状态
a)新建状态 ,Thread被创建,但未start
b)可运行状态: 线程启动进入可执行队列,但未分配cpu时间片执行
c) 运行状态:线程在运行
d) Waiting :这种状态下线程不会被分配cpu时间片,在等待其它线程唤醒,以下方法会进入waiting状态:
1.没有timeout 参数的Object.wait
2.没有timeout参数的Thread.jon
3.:LockSupport.park
e)TimedWaiting :这种状态下线程不会被分配cpu时间片,在等待其它线程唤醒或超时,以下方法会进入TimedWaiting状态:
1.Thread.sleep()
2.设置了Timeout参数的Object.wait(TimeOut)
3.设置了Timeout参数的Thread.join(TimeOut)
4.LockSupport.parkNanos(long nanos)
5.LockSupport.parkUntil(long deadline)
f)Blocked阻塞状态:
线程在等待一个排他锁(synchronized 锁)
g)结束状态
线程执行完成
第十三章 线程安全与锁优化
13.1 线程安全的实现方法
1.互斥同步
synchronized 和ReentrantLock,都是可重入锁具有机同的内存语义,synchronized 语法层面,ReentrantLock API层面上的
两者区别:
1.等待可中断
synchronized 会一直等待持有锁的线程释放锁
ReentrantLock.lockInterruptibly()
会一直等待持有锁的线程释放锁,或其它线程中断此线程。
2.公平锁
synchronized 是非公平锁
ReentrantLock默认也是非公平锁,可以设置为公平锁
3.锁绑定多个条件
synchronized 只允锁定对象为一个隐含的条件,调用其.wait .notify.notifyAll
ReentrantLock 可以通过newCondition 创建多个条件
4. ReentrantLock 可以使用tryLock方法判定是否其它线程持有锁。
适用于多个线程有一条线程处理就可以的场景。
5.同步代码中异常时,synchronized会自动释放锁,ReentrantLock需要在代码finally里释放锁。
2.使用CAS (compare and swap)
此方式不会阻塞线程,性能比互斥锁好,适用于 极短时间内简单操作。
CAS 需要3个参数:变量在内存中的地址,原值,新值。
如果原值与内存地址中的值相同,则用新值替换,否则失败。
CAS存在"ABA"问题。
3.不使用同步机制
3.1 不使用共享数据
方法涉及的数据都是私有或不可变的。
3.2.不可变对象
多线程访问同一个不可变对象是安全的。
3.3. 线程内对象
ThreaLocal
相关推荐
内容概要:本文详细介绍了基于MATLAB GUI界面和卷积神经网络(CNN)的模糊车牌识别系统。该系统旨在解决现实中车牌因模糊不清导致识别困难的问题。文中阐述了整个流程的关键步骤,包括图像的模糊还原、灰度化、阈值化、边缘检测、孔洞填充、形态学操作、滤波操作、车牌定位、字符分割以及最终的字符识别。通过使用维纳滤波或最小二乘法约束滤波进行模糊还原,再利用CNN的强大特征提取能力完成字符分类。此外,还特别强调了MATLAB GUI界面的设计,使得用户能直观便捷地操作整个系统。 适合人群:对图像处理和深度学习感兴趣的科研人员、高校学生及从事相关领域的工程师。 使用场景及目标:适用于交通管理、智能停车场等领域,用于提升车牌识别的准确性和效率,特别是在面对模糊车牌时的表现。 其他说明:文中提供了部分关键代码片段作为参考,并对实验结果进行了详细的分析,展示了系统在不同环境下的表现情况及其潜在的应用前景。
嵌入式八股文面试题库资料知识宝典-计算机专业试题.zip
嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_3.zip
内容概要:本文深入探讨了一款额定功率为4kW的开关磁阻电机,详细介绍了其性能参数如额定功率、转速、效率、输出转矩和脉动率等。同时,文章还展示了利用RMxprt、Maxwell 2D和3D模型对该电机进行仿真的方法和技术,通过外电路分析进一步研究其电气性能和动态响应特性。最后,文章提供了基于RMxprt模型的MATLAB仿真代码示例,帮助读者理解电机的工作原理及其性能特点。 适合人群:从事电机设计、工业自动化领域的工程师和技术人员,尤其是对开关磁阻电机感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解开关磁阻电机特性和建模技术的研究人员,在新产品开发或现有产品改进时作为参考资料。 其他说明:文中提供的代码示例仅用于演示目的,实际操作时需根据所用软件的具体情况进行适当修改。
少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip
内容概要:本文详细介绍了基于PID控制器的四象限直流电机速度驱动控制系统仿真模型及其永磁直流电机(PMDC)转速控制模型。首先阐述了PID控制器的工作原理,即通过对系统误差的比例、积分和微分运算来调整电机的驱动信号,从而实现转速的精确控制。接着讨论了如何利用PID控制器使有刷PMDC电机在四个象限中精确跟踪参考速度,并展示了仿真模型在应对快速负载扰动时的有效性和稳定性。最后,提供了Simulink仿真模型和详细的Word模型说明文档,帮助读者理解和调整PID控制器参数,以达到最佳控制效果。 适合人群:从事电力电子与电机控制领域的研究人员和技术人员,尤其是对四象限直流电机速度驱动控制系统感兴趣的读者。 使用场景及目标:适用于需要深入了解和掌握四象限直流电机速度驱动控制系统设计与实现的研究人员和技术人员。目标是在实际项目中能够运用PID控制器实现电机转速的精确控制,并提高系统的稳定性和抗干扰能力。 其他说明:文中引用了多篇相关领域的权威文献,确保了理论依据的可靠性和实用性。此外,提供的Simulink模型和Word文档有助于读者更好地理解和实践所介绍的内容。
嵌入式八股文面试题库资料知识宝典-2013年海康威视校园招聘嵌入式开发笔试题.zip
少儿编程scratch项目源代码文件案例素材-驾驶通关.zip
小区开放对周边道路通行能力影响的研究.pdf
内容概要:本文探讨了冷链物流车辆路径优化问题,特别是如何通过NSGA-2遗传算法和软硬时间窗策略来实现高效、环保和高客户满意度的路径规划。文中介绍了冷链物流的特点及其重要性,提出了软时间窗概念,允许一定的配送时间弹性,同时考虑碳排放成本,以达到绿色物流的目的。此外,还讨论了如何将客户满意度作为路径优化的重要评价标准之一。最后,通过一段简化的Python代码展示了遗传算法的应用。 适合人群:从事物流管理、冷链物流运营的专业人士,以及对遗传算法和路径优化感兴趣的科研人员和技术开发者。 使用场景及目标:适用于冷链物流企业,旨在优化配送路线,降低运营成本,减少碳排放,提升客户满意度。目标是帮助企业实现绿色、高效的物流配送系统。 其他说明:文中提供的代码仅为示意,实际应用需根据具体情况调整参数设置和模型构建。
少儿编程scratch项目源代码文件案例素材-恐怖矿井.zip
内容概要:本文详细介绍了基于STM32F030的无刷电机控制方案,重点在于高压FOC(磁场定向控制)技术和滑膜无感FOC的应用。该方案实现了过载、过欠压、堵转等多种保护机制,并提供了完整的源码、原理图和PCB设计。文中展示了关键代码片段,如滑膜观测器和电流环处理,以及保护机制的具体实现方法。此外,还提到了方案的移植要点和实际测试效果,确保系统的稳定性和高效性。 适合人群:嵌入式系统开发者、电机控制系统工程师、硬件工程师。 使用场景及目标:适用于需要高性能无刷电机控制的应用场景,如工业自动化设备、无人机、电动工具等。目标是提供一种成熟的、经过验证的无刷电机控制方案,帮助开发者快速实现并优化电机控制性能。 其他说明:提供的资料包括详细的原理图、PCB设计文件、源码及测试视频,方便开发者进行学习和应用。
基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf
嵌入式八股文面试题库资料知识宝典-CC++笔试题-深圳有为(2019.2.28)1.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 V1.5.zip
Android系统开发_Linux内核配置_USB-HID设备模拟_通过root权限将Android设备转换为全功能USB键盘的项目实现_该项目需要内核支持configFS文件系统
C# WPF - LiveCharts Project
少儿编程scratch项目源代码文件案例素材-恐怖叉子 动画.zip
嵌入式八股文面试题库资料知识宝典-嵌⼊式⼯程师⾯试⾼频问题.zip