finalize

JVM中垃圾回收机制如何判断是否死亡?详解引用计数法和可达性分析

老子叫甜甜 提交于 2020-04-07 11:42:50
一、前言   我们都知道Java和C++有一个非常大的区别就是Java有自动的垃圾回收机制,经过半个多世纪的发展,Java已经进入了“自动化”时代,让使用者只需要注重业务逻辑的开发而不需要担心内存的使用情况。那么我们为什么还要学习Java的垃圾回收机制呢?原因很简单:我们不想止于“增删改查工程师”这样的初级水平,一旦程序发生了内存溢出、内存泄漏等问题时,我们可以用已掌握的知识更好的调节和优化我们的代码。在学这章节之前,默认大家已经了解并掌握了Java内存运行时的五个区域的功能:方法区、Java堆、虚拟机栈、本地方法栈、程序计数器。还没有了解过的朋友请先看这里: JVM中五大内存区域 二、判断对象是否死亡 客官们可以先想一下,GC(垃圾回收机制)在清理内存的时候第一件事要做什么?肯定是要先判断内存中的对象是否已经死亡,也就是再也不会被使用了,然后才会去回收这些对象。判断对象是否死亡通常会有两种办法: 引用计数法 和 可达性分析 。 2.1 引用计数法 使用引用计数法,要先给每一个对象中添加一个计数器,一旦有地方引用了此对象,则该对象的计数器加1,如果引用失效了,则计数器减1。这样当计数器为0时,就代表此对象没有被任何地方引用。这种方法实现简单,判定效率也很高,在大部分情况下都是一个比较不错的方法。但是在Java虚拟机中并没有选用引用计数法来管理内存

Java虚拟机详解04----GC算法和种类【重要】

主宰稳场 提交于 2020-04-07 05:39:06
本文主要内容: GC的概念 GC算法     引用计数法(无法解决循环引用的问题,不被java采纳)   根搜索算法   现代虚拟机中的垃圾搜集算法:       标记-清除       复制算法(新生代)       标记-压缩(老年代)   分代收集 Stop-The-World 一、GC的概念: GC:Garbage Collection 垃圾收集 1960年 Lisp使用了GC Java中, GC的对象是Java堆和方法区 (即永久区) 我们接下来对上面的三句话进行一一的解释: (1)GC:Garbage Collection 垃圾收集。这里所谓的垃圾指的是 在系统运行过程当中所产生的一些无用的对象,这些对象占据着一定的内存空间,如果长期不被释放,可能导致OOM 。 在C/C++里是由程序猿自己去申请、管理和释放内存空间,因此没有GC的概念。而在Java中, 后台专门有一个专门用于垃圾回收的线程 来进行监控、扫描,自动将一些无用的内存进行释放,这就是垃圾收集的一个基本思想, 目的在于防止由程序猿引入的人为的内存泄露 。 (2)事实上,GC的历史比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还在胚胎时期时,人们就在思考GC需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何回收? (3)内存区域中的

Java内存泄露

亡梦爱人 提交于 2020-04-06 19:15:39
一、概述 虽然Java有垃圾收集器帮助实现内存自动管理,虽然GC有效的处理了大部分内存,但是并不能完全保证内存的不泄露。 二、内存泄露 内存泄露就是堆内存中不再使用的对象,但是垃圾回收期无法从内存中删除他们的情况,因此他们会被不必要的一直存在。,这种情况会耗尽内存资源并降低系统性能,最终以OOM终止。 垃圾回收器会定期删除未引用的对象,但它永远不会收集那些仍在引用的对象。 内存泄露的症状: 应用程序长时间连续运行时性能严重下降; 应用程序中的OutOfMemoryError堆错误; 自发且奇怪的应用程序崩溃; 应用程序偶尔会耗尽连接对象。 三、Java中内存泄露类型 1、static字段引起的内存泄露 大量使用static字段会潜在的导致内存泄露,在Java中,静态字段通常拥有与整个应用程序相匹配的生命周期。 解决办法:最大限度的减少静态变量的使用;单例模式时,依赖于延迟加载对象而不是立即加载方式。 2、未关闭的资源导致内存泄露 每当创建连接或者打开流时,JVM都会为这些资源分配内存。如果没有关闭连接,会导致持续占有内存。在任意情况下,资源留下的开放连接都会消耗内存,如果我们不处理,就会降低性能,甚至OOM。 解决办法:使用finally块关闭资源;关闭资源的代码,不应该有异常;jdk1.7后,可以使用try-with-resource块。 3、不正确的equals(

Java垃圾收集器

∥☆過路亽.° 提交于 2020-03-29 09:13:46
  概述   说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史远远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还在胚胎时期时,人们就在思考:    GC需要完成的三件事情:      哪些内存需要回收?     什么时候回收?     如何回收?   经过半个世纪的发展,内存的动态分配与内存回收技术已经相当成熟,一切看起来都进入了“自动化”时代,那为什么我们还要去了解GC和内存分配呢?答案很简单:当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。   把时间从半个世纪以前拨回到现在,回到我们熟悉的Java语言。第2章介绍了Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的(尽管在运行期会由JIT编译器进行一些优化,但在本章基于概念模型的讨论中,大体上可以认为是编译期可知的), 因此这几个区域的内存分配和回收都具备确定 性,在这几个区域内不需要过多考虑回收的问题,因为方法结束或线程结束时

面试刷题3:final finally finalize区别?

天涯浪子 提交于 2020-03-24 16:24:21
我是李福春,我在准备面试。今天我们来回答下面的面试常见问题。 final finally finalize区别? 这三个货只是单词的写法类似,实际的使用场景相差很大。 下面一一展开分析: final final修饰类,标识类不可被继承,一定程度保证了提供出去的类的平台安全性; final修饰方法,标识方法不能被重写; final修饰变量,标识变量不能被修改; 在并发场景下可以带来性能提升,因为可以较少额外的同步开销和防御性复制; 但是final不等同于Immutable; 如何实现一个Immutable类: 1.类使用final修饰; 2.成员变量都是private final; 3.构造方法使用深度copy方法赋值; 4.getter方法使用copy-on-write的方式赋值; 看下面的代码,可以看到final和Immutable的区别; //final只保证strlist无法再被赋值,但是可以添加,删除元素等操作 final List<String> strList = new ArrayList<>(); strList.add("Hello"); strList.add("world"); //不变的集合中添加元素会报错 List<String> unmodifiableStrList = List.of("hello", "world");

How finalizable objects takes at least 2 garbage collection cycles before it can be reclaimed?

大城市里の小女人 提交于 2020-03-23 07:24:10
问题 I'm reading this article and I can't really understand how the finalizable objects (objects which override the finalize method) takes at least 2 GC cycles before it can be reclaimed . It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed. Can someone also explain in detail how is it possible for a finalizable object to take more than one GC cycle for reclamation? My logical argument is that when we override finalize method, the

服务器 客户端 实现TCP 1--socket

懵懂的女人 提交于 2020-03-19 04:55:33
附上其他好的文章的链接 https://blog.csdn.net/wo541075754/article/details/66971888 https://blog.csdn.net/u012561176/article/details/48183181 https://blog.csdn.net/u010142437/article/details/18039961 https://blog.csdn.net/alen0217/article/details/42558085 https://blog.csdn.net/qq_34444097/article/details/78955511 小笔记:~Thread t 的意思是声明线程t ,new Thread(this) 的意思是把当前的类实例化为一个线程 该Thread对象调用start()方法后,会执行该对象重写的run()方法,结果也就是Run of Thread,输出完后,run()方法返回,该线程对象的生命周期也就结束了。从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。 finalize方法是Object提供的的实例方法,使用规则如下:当对象不再被任何对象引用时,GC会调用该对象的finalize()方法 finalize(

一个线程池 bug 引发的 GC 思考!

空扰寡人 提交于 2020-03-17 17:22:30
某厂面试归来,发现自己落伍了!>>> 作者:空无 https://segmentfault.com/a/1190000021109130 问题描述 前几天在帮同事排查生产一个线上偶发的线程池错误,逻辑很简单,线程池执行了一个带结果的异步任务。 但是最近有偶发的报错: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@a5acd19 rejected from java.util.concurrent.ThreadPoolExecutor@30890a38\[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0\] 本文中的模拟代码已经问题都是在HotSpot java8 (1.8.0_221)版本下模拟&出现的 下面是模拟代码,通过Executors.newSingleThreadExecutor创建一个单线程的线程池,然后在调用方获取Future的结果 public class ThreadPoolTest { public static void main(String\[\] args) { final ThreadPoolTest

垃圾回收器

痞子三分冷 提交于 2020-03-08 12:56:56
对象死亡过程 一个对象的真正死亡,至少要经过两轮标记 判定对象死亡后,进行第一次标记,并进行筛选,筛选条件:有没有必要执行finalize()。对象没有覆盖finalize()或者覆盖的finalize()已经执行过,都视为没有必要执行finalize()。 如果没有必要执行finalize(),稍后会进行第二次标记,根据垃圾回收算法,进行垃圾回收。 如果有必要执行finalize(),则执行finalize(),在此方法中,对象只要活过来,就不会被垃圾回收。 任何一个对象的finalize()方法都只会被系统调用一次,不会调用第二次。 关于方法区的垃圾回收 方法区的垃圾回收主要两个部分:废弃的常量和无用的类。 废弃的常量:和回收堆中的对象差不多。 无用的类:需要同时满足下面的三个条件: 1.堆中没有该类的任何实例。 2.加载该类的ClassLoader被回收。 3.该类的Class对象没有任何地方被引用。 垃圾回收算法 1.标记-清除算法:标记出需要回收的对象,在标记完成后统一回收被标记的对象。 两个缺点:效率低,会产生大量的不连续的内存碎片。 2.复制算法:将内存分为两块,只使用其中的一块内存,回收时,将存活的对象复制到另一块内存上,然后将原先的内存进行清理。 缺点:内存变为原来的一般代价高昂,当存活的对象多时,效率更低。 3.标记-整理算法:标记需要回收的对象