`

OSGi 内存泄露

阅读更多

问题背景:

1.内存泄漏:OSGi容器中,不同版本的类永久共存。

 

 OSGi 动态化模块系统,允许不同版本的相同类共存,OSGi只需在方法区内存加载新的classloader。

 但是客观上会占用更多的内存。如果对OSGi动态性使用不当,可能会因为不正确持有某个过期模块(被更新或卸载的模块)中一个类的实例,导致该类的类加载器无法被回收,进而导致该类加载器下所有类都无法被GC回收掉。

为了防止保留类加载器带来的内存泄露,我们必须使用弱键和弱值。目标是不在内存中保持一个已卸载的bundle的类空间。我们必须使用弱值,因为每个映射项目的值(BridgeClassLoader)都强引用着键(ClassLoader),于是以此方式否定它的弱点。这是WeakHashMap javadoc规定的标准建议。通过使用一个弱缓存我们避免了跟踪所有的bundle,而且不必对他们的生命周期做出反应。

问题二:运行时的ClassNotFoundException

情形1: 间接引用带来的问题

原因:Plugin_1 没有直接使用Plugin_2Java文件,但运行时使用了Plugin_2中的Jar包中的文件。

解决措施:Plugin_2中的Jar包导出来, 同时在Plugin_1中导入这些包。

 

情形2: 利用String反射到类或对象的时候出现的问题

Plugin_1涉及到由String转化为类对象Plugin_2_ClassA(Plugin_2_ClassA表示Plugin_2中的Class  A)的操作, 这个时候调用非常隐晦,也需要按照情形1进行处理。

 

情形3: 加载顺序不对带来的问题

IDE环境下, 这个问题出现在控制台中

IDE环境下, 这个问题出现在configuration目录下面的Log目录中。

 

1. 如果是IDE环境下出现的问题,   Run Configuration中配置一下启动顺序

2. 发布环境下, config.ini 需要做新的调整,先加载底层插件,再加载依赖插件,最后加载不被任何插件依赖的项目 (参见文章开始的参考资料4)

3. 发布环境下, 如果问题一再出现, 请删除\configuration目录下的org.eclipse.osgi 目录, 再进行启动

 

 

OSGi类加载流程

OSGi每个模块都有自己独立的classpath

如何实现这一点呢?是因为OSGi采取了不同的类加载机制:

——OSGi为每个bundle提供一个类加载器,该加载器能够看到bundle Jar文件内部的类和资源;

——为了让bundle能互相协作,可以基于依赖关系,从一个bundle类加载器委托到另一个bundle类加载器。

 

JavaJ2EE的类加载模型都是层次化的,只能委托给上一层类加载器;

 

OSGi类加载模型则是网络图状的,可以在bundle间互相委托。——这样更合理,因为bundle间的依赖关系并不是层次化的。

 

 

优点

找不到类时的错误提示更友好。假如bundleE不存在,则bundleC就不会被解析成功,会有错误消息提示为何未能解析;而不是报错ClassNotFoundExceptionNoClassDefFoundError

效率更高。

 

在标准Java类加载模型中,总是会在classpath那一长串列表中进行查找;而OSGi类加载器能立即知道去哪里找类。

 

流程

Step 1: 检查是否java.*,或者在bootdelegation中定义

bundle类加载器需要加载一个类时,首先检查包名是否以java.*开头,或者是否在一个特定的配置文件(org.osgi.framework.bootdelegation)中定义。如果是,则bundle类加载器立即委托给父类加载器(通常是Application类加载器)。

 

这么做有两个原因:

唯一能够定义java.*包的类加载器是bootstrap类加载器,这个规则是JVM要求的。如果OSGI bundle类加载器试图加载这种类,则会抛Security Exception

一些JVM错误地假设父加载器委托永远会发生,内部VM类就能够通过任何类加载器找到特定的其他内部类。所以OSGi提供了org.osgi.framework.bootdelegation属性,允许对特定的包(即那些内部VM类)使用父加载器委托。

 

Step 2: 检查是否在Import-Package中声明

检查是否在Import-Package中声明。如果是,则找到导出包的bundle,将类加载请求委托给该bundle的类加载器。如此往复。

 

Step 3: 检查是否在Require-Bundle中声明

检查是否在Require-Bundle中声明。如果是,则将类加载请求委托给required bundle的类加载器。

 

Step 4: 检查是否bundle内部类

检查是否是该bundle内部的类,即当前JAR文件中的类。

 

Step5:  检查fragment

搜索可能附加在当前bundle上的fragment中的内部类。

 

什么是fragment

Fragment bundleOSGi 4引入的概念,它是一种不完整的bundle,必须要附加到一个host bundle上才能工作;fragment能够为host bundle添加类或资源,在运行时,fragment中的类会合并到host bundle的内部classpath中。

 

fragment有什么作用?

 

【场景1bundle中有针对特定平台的代码

假设bundle对不同平台的实现方式稍有不同,WindowsLinux下代码有不同之处,即bundle中有针对特定平台的代码。

我们应该为每个平台提供不同的bundle吗?——显然不能,因为那会造成代码重复。

 

或者将共同代码放到bundle A中,Windows特定的那部分代码放到bundle Pwin中,Linux特定的那部分代码放到bundle Plinux中。——有问题:Pwin肯定要依赖A中某些包,我们就必须在A中导出这些包,如果只有Pwin用到这些包岂不破坏封装性。

 

最好的解决方法是把Pwin作为fragment,附加到A中。这样Pwin就能看到A中的所有包,A也能看到Pwin的所有包。

 

【场景2】针对不同国家用户提供不同的i18n

 

GUI程序通常会通过properties文件定义i18n信息,可以将不同的i18n存到不同的fragment中。运行时用户只需要下载host bundle以及特定的i18n fragment即可,不需要把其他国家的i18n也下载下来。

 

 

Step6: 动态类加载

 

OSGi:灵活的类加载器架构

高并发环境下死锁问题

都会锁定自己的类加载器实例。

 

分享到:
评论

相关推荐

    spring,jvm,osgi文档

    了解JVM的内存模型,如堆内存(Heap)、方法区(Method Area)、栈内存(Stack)等,对于优化性能和解决内存泄漏问题至关重要。此外,理解垃圾回收的工作原理,包括分代收集、并发标记清除等策略,也是JVM调优的关键...

    OutOfMemoryError.docx

    2. **修复内存泄漏**:使用内存分析工具,如MAT(Memory Analyzer Tool)找出内存泄漏源,并修复相关代码。 3. **调整JVM参数**:增加JVM的堆内存大小,或者调整新生代和老年代的比例,以适应应用的需求。同时,...

    底层篇.pdf

    直接内存和堆外内存是指不在JVM堆中分配的内存,它们可以绕过JVM的内存管理,提供更高的性能,但可能导致内存泄漏。 TLAB(Thread Local Allocation Buffer)是JVM为每个线程预先分配的一小块内存,用于在堆上快速...

    java调用插件代码.rar

    确保在正确的时间加载和释放资源,避免内存泄漏和其他问题。 9. **安全性与隔离**: 调用插件时要考虑安全性,防止恶意插件对主程序造成影响。使用沙箱环境或限制插件的权限是一种常见的安全策略。 10. **插件的...

    蚂蚁移动App平台-超级App引擎-对外-v1.0.3

    4. 性能优化实践:通过技术手段对资源进行优化,包括但不限于内存管理、图片解码转移到Native层、内存泄漏的清理、主线程优先级调整等。通过框架重构、虚拟机调优等手段,达到减少GC次数和提升应用性能的目的。 5. ...

    Eclipse精要与高级开发技术(PDF)

    - 内存分析:介绍Eclipse内存分析工具MAT(Memory Analyzer Tool),用于检测和解决内存泄漏问题。 7. **高级主题** - SWT和JFace:解析Eclipse图形用户界面的基础——SWT和JFace库,如何创建自定义UI组件。 - ...

    Eclipse精要与高级开发技术

    - **内存分析**:理解如何使用Memory Analyzer Tool (MAT) 分析和解决内存泄漏问题。 7. **团队协作** - **版本控制系统集成**:通过Eclipse与SVN、Git等版本控制系统的集成,实现代码版本管理和协同开发。 - **...

    Eclipse详细参考文档.rar

    - 了解内存分析工具,监控应用内存占用,防止内存泄漏。 - 配置启动参数,调整Eclipse性能,如增加JVM内存分配。 - 使用工作台性能监视器,找出性能瓶颈。 7. **Eclipse插件推荐**: - Mylyn:任务管理工具,...

    互联网大厂Java工程师岗位面试真题

    GC的主要目标是回收不再使用的对象所占用的内存,防止内存泄漏。 【类加载机制】 Java的类加载机制遵循“双亲委派模型”,即类加载器首先尝试由其父加载器加载,只有父加载器无法加载时才由当前加载器加载。自定义...

    eclipse-rcp-2023-12-R-linux-gtk-aarch64.tar.gz

    开发者需要关注内存管理,避免内存泄漏;合理使用线程,防止阻塞UI;以及利用SWT的本地化特性,提高图形渲染效率。 6. **社区与生态系统**:Eclipse RCP背后有一个庞大的开发者社区,提供了丰富的教程、文档和示例...

    Eclipse编程技术与实例

    - **内存分析**:学习如何使用Eclipse的内置性能分析工具,进行内存泄漏检测和性能调优。 - **启动速度提升**:给出优化Eclipse启动速度和运行效率的建议。 通过本书的深入学习,读者不仅可以掌握Eclipse的基本...

    ClassLoader总结

    这对于长时间运行的应用来说可能造成内存泄漏。 7. ClassLoader与反射: 反射API(如Class.forName())在查找类时也会涉及到ClassLoader。开发者可以指定ClassLoader来加载特定的类,这在处理动态加载或插件系统时...

    eclipse开发帮助

    - **内存分析器**:Eclipse内含性能分析工具,可以帮助识别内存泄漏和性能瓶颈。 - **启动优化**:通过调整启动配置,如减少启动插件,可以加快Eclipse的启动速度。 以上只是Eclipse开发帮助中的一小部分,实际...

    eclipse_plug_ins_third_edition.pdf

    书中会分享一些性能调优的技巧,如何避免内存泄漏,优化启动速度,以及如何处理并发问题。 9. **案例研究**:通过实际的案例分析,读者可以更直观地了解如何将所学知识应用于实际项目中,提高解决实际问题的能力。 ...

    插件应用程序框架设计-Engine框架案例

    生命周期管理确保了插件的正确加载和卸载,防止了可能的内存泄漏或状态不一致问题。 4. **接口与通信机制**:在Engine框架中,核心应用程序与插件之间的交互依赖于定义良好的接口。这些接口定义了插件可以提供的...

    kotlin-docs

    - **内存安全**:通过使用智能指针和引用计数来管理内存,从而避免常见的内存泄漏问题。 - **互操作性**:可以与 C/C++ 代码交互,为跨平台移动开发提供了灵活性。 #### 六、Kotlin 新特性介绍 - **Kotlin 1.1**:...

    大厂的Android面试题.pdf

    - **AsyncTask缺陷**:AsyncTask不适合长时间运行的任务,可能会导致内存泄漏等问题。 - **设计模式**:观察者模式用于实现对象之间的解耦通知;单例模式保证一个类只有一个实例。 - **数学问题**:解决这类问题...

Global site tag (gtag.js) - Google Analytics