1.javaä¸ä¸ªå¼ç¨ç±»å
2.Andorid进阶一:LeakCanary源码分析,从头到尾搞个明白
3.Java中弱引用 丨 12分钟通过案例带你深入源码,分析其原理
javaä¸ä¸ªå¼ç¨ç±»å
åç§å¼ç¨ç±»å
æä»¥å¨ JDK.1.2 ä¹åï¼Java 对å¼ç¨çæ¦å¿µè¿è¡äºæ©å ï¼å°å¼ç¨å为äºï¼å¼ºå¼ç¨ï¼Strong Referenceï¼ã软å¼ç¨ï¼Soft Referenceï¼ãå¼±å¼ç¨ï¼Weak Referenceï¼ãèå¼ç¨ï¼Phantom Referenceï¼4 ç§ï¼è¿ 4 ç§å¼ç¨ç强度ä¾æ¬¡åå¼±ã
ä¸ï¼å¼ºå¼ç¨
Javaä¸é»è®¤å£°æçå°±æ¯å¼ºå¼ç¨ï¼æ¯å¦ï¼
Object obj = new Object(); //åªè¦objè¿æåObject对象ï¼Object对象就ä¸ä¼è¢«åæ¶
obj = null; //æå¨ç½®null
åªè¦å¼ºå¼ç¨åå¨ï¼åå¾åæ¶å¨å°æ°¸è¿ä¸ä¼åæ¶è¢«å¼ç¨ç对象ï¼åªæå åä¸è¶³æ¶ï¼JVMä¹ä¼ç´æ¥æåºOutOfMemoryErrorï¼ä¸ä¼å»åæ¶ãå¦ææ³ä¸æ强å¼ç¨ä¸å¯¹è±¡ä¹é´çèç³»ï¼å¯ä»¥æ¾ç¤ºçå°å¼ºå¼ç¨èµå¼ä¸ºnullï¼è¿æ ·ä¸æ¥ï¼JVMå°±å¯ä»¥éæ¶çåæ¶å¯¹è±¡äº
äºï¼è½¯å¼ç¨
软å¼ç¨æ¯ç¨æ¥æè¿°ä¸äºéå¿ éä½ä»æç¨ç对象ãå¨å å足å¤çæ¶åï¼è½¯å¼ç¨å¯¹è±¡ä¸ä¼è¢«åæ¶ï¼åªæå¨å åä¸è¶³æ¶ï¼ç³»ç»åä¼åæ¶è½¯å¼ç¨å¯¹è±¡ï¼å¦æåæ¶äºè½¯å¼ç¨å¯¹è±¡ä¹åä»ç¶æ²¡æ足å¤çå åï¼æä¼æåºå å溢åºå¼å¸¸ãè¿ç§ç¹æ§å¸¸å¸¸è¢«ç¨æ¥å®ç°ç¼åææ¯ï¼æ¯å¦ç½é¡µç¼åï¼å¾çç¼åçã
å¨ JDK1.2 ä¹åï¼ç¨java.lang.ref.SoftReferenceç±»æ¥è¡¨ç¤ºè½¯å¼ç¨ã
ä¸é¢ä»¥ä¸ä¸ªä¾åæ¥è¿ä¸æ¥è¯´æ强å¼ç¨å软å¼ç¨çåºå«ï¼
å¨è¿è¡ä¸é¢çJava代ç ä¹åï¼éè¦å é ç½®åæ° -Xms2M -Xmx3Mï¼å° JVM çåå§å å设为2Mï¼æ大å¯ç¨å å为 3Mã
é¦å å æ¥æµè¯ä¸ä¸å¼ºå¼ç¨ï¼å¨éå¶äº JVM å åçåæä¸ï¼ä¸é¢ç代ç è¿è¡æ£å¸¸
public class TestOOM {
public static void main(String[] args) {
testStrongReference();
}
private static void testStrongReference() {
// å½ new byte为 1M æ¶ï¼ç¨åºè¿è¡æ£å¸¸
byte[] buff = new byte[ * * 1];
}
}
ä½æ¯å¦ææ们å°
byte[] buff = new byte[ * * 1];
æ¿æ¢ä¸ºå建ä¸ä¸ªå¤§å°ä¸º 2M çåèæ°ç»
byte[] buff = new byte[ * * 2];
åå åä¸å¤ä½¿ç¨ï¼ç¨åºç´æ¥æ¥éï¼å¼ºå¼ç¨å¹¶ä¸ä¼è¢«åæ¶
æ¥çæ¥çä¸ä¸è½¯å¼ç¨ä¼æä»ä¹ä¸ä¸æ ·ï¼å¨ä¸é¢ç示ä¾ä¸è¿ç»åå»ºäº ä¸ªå¤§å°ä¸º 1M çåèæ°ç»ï¼å¹¶èµå¼ç»äºè½¯å¼ç¨ï¼ç¶å循ç¯éåå°è¿äºå¯¹è±¡æå°åºæ¥ã
public class TestOOM {
private static List<Object> list = new ArrayList<>();
public static void main(String[] args) {
testSoftReference();
}
private static void testSoftReference() {
for (int i = 0; i < ; i++) {
byte[] buff = new byte[ * ];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主å¨éç¥åå¾åæ¶
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
}
}
æå°ç»æï¼
æ们åç°æ 论循ç¯å建å¤å°ä¸ªè½¯å¼ç¨å¯¹è±¡ï¼æå°ç»ææ»æ¯åªææåä¸ä¸ªå¯¹è±¡è¢«ä¿çï¼å ¶ä»çobjå ¨é½è¢«ç½®ç©ºåæ¶äºã
è¿é就说æäºå¨å åä¸è¶³çæ åµä¸ï¼è½¯å¼ç¨å°ä¼è¢«èªå¨åæ¶ã
å¼å¾æ³¨æçä¸ç¹ , å³ä½¿æ byte[] buff å¼ç¨æå对象, ä¸ buff æ¯ä¸ä¸ªstrong reference, ä½æ¯ SoftReference sr æåç对象ä»ç¶è¢«åæ¶äºï¼è¿æ¯å 为Javaçç¼è¯å¨åç°äºå¨ä¹åç代ç ä¸, buff å·²ç»æ²¡æ被使ç¨äº, æ以èªå¨è¿è¡äºä¼åã
å¦ææ们å°ä¸é¢ç¤ºä¾ç¨å¾®ä¿®æ¹ä¸ä¸ï¼
private static void testSoftReference() {
byte[] buff = null;
for (int i = 0; i < ; i++) {
buff = new byte[ * ];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主å¨éç¥åå¾åæ¶
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
System.out.println("buff: " + buff.toString());
}
å buff ä¼å 为强å¼ç¨çåå¨ï¼èæ æ³è¢«åå¾åæ¶ï¼ä»èæåºOOMçé误ã
å¦æä¸ä¸ªå¯¹è±¡æä¸å©ä¸çå¼ç¨æ¯è½¯å¼ç¨ï¼é£ä¹è¯¥å¯¹è±¡æ¯è½¯å¯åçï¼softly reachableï¼ãåå¾æ¶éå¨å¹¶ä¸åå ¶æ¶éå¼±å¯åç对象ä¸æ ·å°½éå°æ¶é软å¯åç对象ï¼ç¸åï¼å®åªå¨çæ£ âéè¦â å åæ¶ææ¶é软å¯åç对象ã
ä¸ï¼å¼±å¼ç¨
å¼±å¼ç¨çå¼ç¨å¼ºåº¦æ¯è½¯å¼ç¨è¦æ´å¼±ä¸äºï¼æ 论å åæ¯å¦è¶³å¤ï¼åªè¦ JVM å¼å§è¿è¡åå¾åæ¶ï¼é£äºè¢«å¼±å¼ç¨å ³èç对象é½ä¼è¢«åæ¶ãå¨ JDK1.2 ä¹åï¼ç¨ java.lang.ref.WeakReference æ¥è¡¨ç¤ºå¼±å¼ç¨ã
æ们以ä¸è½¯å¼ç¨åæ ·çæ¹å¼æ¥æµè¯ä¸ä¸å¼±å¼ç¨ï¼
private static void testWeakReference() {
for (int i = 0; i < ; i++) {
byte[] buff = new byte[ * ];
WeakReference<byte[]> sr = new WeakReference<>(buff);
list.add(sr);
}
System.gc(); //主å¨éç¥åå¾åæ¶
for(int i=0; i < list.size(); i++){
Object obj = ((WeakReference) list.get(i)).get();
System.out.println(obj);
}
}
æå°ç»æï¼
å¯ä»¥åç°ææ被弱å¼ç¨å ³èç对象é½è¢«åå¾åæ¶äºã
åï¼èå¼ç¨
èå¼ç¨æ¯æå¼±çä¸ç§å¼ç¨å ³ç³»ï¼å¦æä¸ä¸ªå¯¹è±¡ä» ææèå¼ç¨ï¼é£ä¹å®å°±å没æä»»ä½å¼ç¨ä¸æ ·ï¼å®éæ¶å¯è½ä¼è¢«åæ¶ï¼å¨ JDK1.2 ä¹åï¼ç¨ PhantomReference ç±»æ¥è¡¨ç¤ºï¼éè¿æ¥çè¿ä¸ªç±»çæºç ï¼åç°å®åªæä¸ä¸ªæé å½æ°åä¸ä¸ª get() æ¹æ³ï¼èä¸å®ç get() æ¹æ³ä» ä» æ¯è¿åä¸ä¸ªnullï¼ä¹å°±æ¯è¯´å°æ°¸è¿æ æ³éè¿èå¼ç¨æ¥è·å对象ï¼èå¼ç¨å¿ é¡»è¦å ReferenceQueue å¼ç¨éåä¸èµ·ä½¿ç¨ã
public class PhantomReference<T> extends Reference<T> {
/
*** Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
é£ä¹ä¼ å ¥å®çæé æ¹æ³ä¸ç ReferenceQueue åæ¯å¦ä½ä½¿ç¨çå¢ï¼
äºï¼å¼ç¨éåï¼ReferenceQueueï¼
å¼ç¨éåå¯ä»¥ä¸è½¯å¼ç¨ãå¼±å¼ç¨ä»¥åèå¼ç¨ä¸èµ·é å使ç¨ï¼å½åå¾åæ¶å¨åå¤åæ¶ä¸ä¸ªå¯¹è±¡æ¶ï¼å¦æåç°å®è¿æå¼ç¨ï¼é£ä¹å°±ä¼å¨åæ¶å¯¹è±¡ä¹åï¼æè¿ä¸ªå¼ç¨å å ¥å°ä¸ä¹å ³èçå¼ç¨éåä¸å»ãç¨åºå¯ä»¥éè¿å¤æå¼ç¨éåä¸æ¯å¦å·²ç»å å ¥äºå¼ç¨ï¼æ¥å¤æ被å¼ç¨ç对象æ¯å¦å°è¦è¢«åå¾åæ¶ï¼è¿æ ·å°±å¯ä»¥å¨å¯¹è±¡è¢«åæ¶ä¹åéåä¸äºå¿ è¦çæªæ½ã
Andorid进阶一:LeakCanary源码分析,从头到尾搞个明白
内存优化掌握了吗?知道如何定位内存问题吗?面试官和蔼地问有些拘谨的小张。小张回答道:“就是用LeakCanary检测一下泄漏,找到对应泄漏的免费源码网有哪些地方,修改错误的代码,回收没回收的引用,优化生命周期线程的依赖关系。”“那你了解LeakCanary分析内存泄漏的原理吗?”面试官追问。“不好意思,平时没有注意过。”小张心想:面试怎么总问这个,我只是钱包APP源码下载一个普通的程序员。
前言:
应用性能优化是开发中不可或缺的一环,而内存优化尤为重要。内存泄漏导致的内存溢出崩溃和内存抖动带来的卡顿不流畅,都在切实影响着用户体验。LeakCanary常用于定位内存泄漏问题,是时候深入理解它的工作机制了。
名词理解:
hprof:hprof文件是Java的内存快照文件,格式后缀为.hprof,在LeakCanary中用于内存分析。WeakReference:弱引用,当对象仅被weak reference指向,没有任何其他strong reference指向时,在GC运行时,茶杯狗源码搭建这个对象就会被回收,不论当前内存空间是否足够。在LeakCanary中用于监测被回收的无用对象是否被释放。Curtains:Square的另一个开源框架,用于处理Android窗口的集中式API,在LeakCanary中用于监测window rootView在detach后的内存泄漏。
目录:
本文将从以下几个方面进行分析:
一,怎么用?
查看官网文档可以看出,使用LeakCanary非常简单,只需添加相关依赖即可。debugImplementation只在debug模式的编译和最终的debug apk打包时有效。LeakCanary的初始化代码通过ContentProvider进行,会在AppWatcherInstaller类的上货软件源码下载oncreate方法中调用真正的初始化代码AppWatcher.manualInstall(application)。在AndroidManifest.xml中注册该provider,注册的ContentProvider会在application启动的时候自动回调oncreate方法。
二,官方阐述
安装LeakCanary后,它会通过4个步骤自动检测并报告内存泄漏:如果ObjectWatcher在等待5秒并运行垃圾收集后没有清除持有的弱引用,则被监视的对象被认为是保留的,并且可能会泄漏。LeakCanary会将其记录到Logcat中,并在泄漏列表展示中用Library Leak标签标记。LeakCanary附带一个已知泄漏的数据库,通过引用名称的模式匹配来识别泄漏,如Library Leaks。对于无法识别的ae全息展示源码泄漏,可以报告并自定义已知库泄漏的列表。
三,监测activity,fragment,rootView和viewmodel
初始化的代码关键在于AppWatcher作为Android平台使用ObjectWatcher封装的API中心,自动安装配置默认的监听。我们分析了四个默认监听的Watcher,包括ActivityWatcher,FragmentAndViewModelWatcher,RootViewWatcher和ServiceWatcher,分别用于监测activity,fragment,rootView和service的内存泄漏。
四,ObjectWatcher保留对象检查分析
LeakCanary通过ObjectWatcher监控内存泄漏,我们深入分析了其检查过程,包括创建弱引用,检查对应key对象的保留,以及内存快照转储和内存分析。
五,总结
本文全面分析了LeakCanary的实现原理,从安装、使用到内存泄漏的检测和分析,详细介绍了各个组件的作用和工作流程。通过深入理解LeakCanary,开发者可以更有效地定位和解决内存泄漏问题,优化应用性能。阅读源码不仅能深入了解LeakCanary的工作机制,还能学习到内存泄漏检测的通用方法和技巧。
Java中弱引用 丨 分钟通过案例带你深入源码,分析其原理
深入理解Java中的弱引用:分钟带你探索原理与应用
弱引用在Java中扮演着微妙的角色,它并非阻止垃圾回收,而是提供了一种特殊关联方式。JDK官方解释,弱引用主要用于实现那些不需要阻止其键或值被回收的映射。弱引用的出现,是为了在不再使用对象时,让垃圾回收器在合适的时候自动回收,从而避免内存溢出问题。
让我们通过实例来了解。想象一个场景,当我们维护一个map,存储了大量生命周期短暂的对象,如果key和value都由强引用指向,即使我们设置为null,对象仍不会被回收,因为map作为静态变量,其生命周期长。这时,弱引用的介入就显得尤为重要。通过将key变为弱引用,即使对象不再被方法引用,也能在垃圾回收时被释放,避免内存耗尽。
弱引用的使用并不复杂,只需将HashMap替换为WeakHashMap,将key变为WeakReference。当我们不再需要这些对象时,它们会被自动回收,如在上述例子中,输出的size为0,就证明了这一点。然而,这并不意味着value和entry会自动回收,这时WeakHashMap的expungeStaleEntries方法就发挥作用,它会清理不再引用的对象。
引用队列在此过程中扮演了关键角色,它帮助我们在弱引用被回收时高效地找到并处理相关对象,避免了遍历整个数据结构的性能消耗。在使用弱引用时,需要注意检查对象是否已被回收,以防空指针异常。
通过这些深入解析,我们对弱引用有了全面的认识,它在内存管理中的巧妙应用,为我们提供了一种解决内存溢出的有效手段。