java去掉特殊符号Java:如何避免在 Java 中使用双括号初始化 没有看后悔
voidlogSavingTicket( StringticketId) { Map< String, Object> metadata = newMainActivity$ 1( this, tic...
欢迎大家来到我的博客!今天我为大家准备了1篇精彩的文章,希望能够引起大家的兴趣并有所收获。
原标题:如何避免在 Java 中使用双括号初始化| CSDN(ID:CSDNnews)
结论先行避免像这样,在 Java 中使用双括号初始化:newHashMap {{ put( "key", value); }};内存泄漏追踪我最近正在 LeakCanary
看到了以下内存泄漏追踪信息:┬───│ GC Root: Global variable innativecode │├─ com.bugsnag.android.AnrPlugin instance│ Leaking: UNKNOWN
│ ↓ AnrPlugin.client│ ~~~~~~├─ com.bugsnag.android.Client instance│ Leaking: UNKNOWN│ ↓ Client.breadcrumbState
│ ~~~~~~~~~~~~~~~├─ com.bugsnag.android.BreadcrumbState instance│ Leaking: UNKNOWN│ ↓ BreadcrumbState.store
│ ~~~~~├─ com.bugsnag.android.Breadcrumb[] array│ Leaking: UNKNOWN│ ↓ Breadcrumb[ 494] │ ~~~~~├─ com.bugsnag.android.Breadcrumb instance
│ Leaking: UNKNOWN│ ↓ Breadcrumb.impl│ ~~~~├─ com.bugsnag.android.BreadcrumbInternal instance│ Leaking: UNKNOWN
│ ↓ BreadcrumbInternal.metadata│ ~~~~~~~~├─ com.example.MainActivity$ 1instance │ Leaking: UNKNOWN│ Anonymous subclass of java.util.HashMap
│ ↓ MainActivity$ 1. this$ 0│ ~~~~~~╰→ com.example.MainActivity instanceLeaking: YES (Activity#mDestroyed
istrue) 当打开1个内存泄漏追踪日志时,我首先会看底部的对象,了解它的生命周期,这将帮助我理解内存泄漏追踪中的其他对象是否应该有相同的生命周期在底部,我们看到:╰→ com.example.MainActivity。
instanceLeaking: YES( Activity#mDestroyedistrue) Activity已经被销毁,应该已被垃圾回收器给回收掉了,但它仍驻留在内存中此时,我开始在内存泄漏追踪日志中寻找已知类型,并尝试弄清楚它们是否属于同1个被销毁的范围(=> 正在泄漏)或更高的范围(=> 没有泄漏)。
在顶部,我们看到:├─ com.bugsnag.android.Clientinstance│ Leaking: UNKNOWN我们的BugSnag客户端是1个用于分析崩溃报告单例,由于每个应用我们创建1个实例,所以它没有泄漏。
├─ com.bugsnag.android.Clientinstance│ Leaking: NO所以我们现在需要转变焦点,特别关注从最后1个Leaking: NO到第1个 Leaking: YES的部分:
…├─ com.bugsnag.android.Client instance│ Leaking: NO│ ↓ Client.breadcrumbState│ ~~~~~~~~~~~~~~~├─ com.bugsnag.android.BreadcrumbState instance
│ Leaking: UNKNOWN│ ↓ BreadcrumbState.store│ ~~~~~├─ com.bugsnag.android.Breadcrumb[] array│ Leaking: UNKNOWN
│ ↓ Breadcrumb[494]│ ~~~~~├─ com.bugsnag.android.Breadcrumb instance│ Leaking: UNKNOWN│ ↓ Breadcrumb.impl
│ ~~~~├─ com.bugsnag.android.BreadcrumbInternal instance│ Leaking: UNKNOWN│ ↓ BreadcrumbInternal.metadata
│ ~~~~~~~~├─ com.example.MainActivity $1instance │ Leaking: UNKNOWN│ Anonymous subclass of java.util.HashMap
│ ↓ MainActivity $1.this $0│ ~~~~~~╰→ com.example.MainActivity instanceLeaking: YES (Activity #mDestroyed is true)
BugSnag 客户端保持了1个面包屑的环形缓冲区这些应该保留在内存中,它们也没有泄漏所以让我们跳过上述内容,从上面这里继续分析:├─ com.bugsnag.android.BreadcrumbInternal。
instance│ Leaking: NO我们只需要关注从最后1个Leaking: NO到第1个Leaking: YES的部分:…├─ com.bugsnag.android.BreadcrumbInternal instance
│ Leaking: NO│ ↓ BreadcrumbInternal.metadata│ ~~~~~~~~├─ com.example.MainActivity $1instance │ Leaking: UNKNOWN
│ Anonymous subclass of java.util.HashMap│ ↓ MainActivity $1.this $0│ ~~~~~~╰→ com.example.MainActivity instance
Leaking: YES (Activity #mDestroyed is true)BreadcrumbInternal.metadata :内存泄漏追踪通过面包屑实现的元数据字段也就是说:记录到 BugSnag 的面包屑之1有1个元数据映射,这是1个。
HashMap的匿名子类 ,它保留对外部类的引用,这个外部类就是被销毁的 Activity 让我们看看我们在MainActivity中记录面包屑的地方:voidlogSavingTicket( String。
ticketId) { Map metadata = newHashMap {{ put( "ticketId", ticketId);
}};bugsnagClient.leaveBreadcrumb( "Saving Ticket", metadata, LOG); }这段代码利用了1个被称为“双括号初始化” 的有趣的 Java 代码块 。
它允许你创建1个HashMap,并通过添加代码到HashMap的匿名子类的构造函数中同时初始化它newHashMap {{ put( "ticketId", ticketId); 。
}};Java 的匿名类总是隐式地引用其外部类 因此,这段代码:voidlogSavingTicket( StringticketId) { Map metadata = 。
newHashMap {{ put( "ticketId", ticketId); }};bugsnagClient.leaveBreadcrumb( "Saving Ticket"
, metadata, LOG); }实际上被编译为:classMainActivity$1 extendsHashMap { private final MainActivity
this$ 1; MainActivity$ 1(MainActivity this$ 1, StringticketId) { this.this$ 1= this$ 1; put( "ticketId"
, ticketId); }}voidlogSavingTicket( StringticketId) { Map metadata = newMainActivity$
1( this, ticketId); bugsnagClient.leaveBreadcrumb( "Saving Ticket", metadata, LOG); }结果,这个 breadcrumb 就1直持有对已销毁的 activity 实例的引用。
总结尽管使用 Java 的双括号初始化看起来很"炫酷",但它会无故地额外创建类,可能会导致内存泄漏因此避免在 Java 中使用双括号初始化你可以用上面这种更安全的方式来解决这个问题:Map< String。
, Object> metadata = newHashMap<>; metadata.put( "ticketId", ticketId); bugsnagClient.leaveBreadcrumb(
"Saving Ticket", metadata, LOG); 或者利用Collections.singletonMap进1步简化代码:Map metadata = singletonMap(
"ticketId", ticketId); bugsnagClient.leaveBreadcrumb( "Saving Ticket", metadata, LOG); 或者,直接将文件转换为 Kotlin。
这就是今天要分享的内容了。希望你能喜欢这篇文章。如果你觉得有价值的话,请给我1个赞吧。也可以关注我。收藏我的文章。让我们1起探索更多有意思的事情吧。
当前非电脑浏览器正常宽度,请使用移动设备访问本站!