问题背景:
1.内存泄漏:OSGi容器中,不同版本的类永久共存。
OSGi 动态化模块系统,允许不同版本的相同类共存,OSGi只需在方法区内存加载新的classloader。
但是客观上会占用更多的内存。如果对OSGi动态性使用不当,可能会因为不正确持有某个过期模块(被更新或卸载的模块)中一个类的实例,导致该类的类加载器无法被回收,进而导致该类加载器下所有类都无法被GC回收掉。
为了防止保留类加载器带来的内存泄露,我们必须使用弱键和弱值。目标是不在内存中保持一个已卸载的bundle的类空间。我们必须使用弱值,因为每个映射项目的值(BridgeClassLoader)都强引用着键(ClassLoader),于是以此方式否定它的“弱点”。这是WeakHashMap javadoc规定的标准建议。通过使用一个弱缓存我们避免了跟踪所有的bundle,而且不必对他们的生命周期做出反应。
问题二:运行时的ClassNotFoundException
情形1: 间接引用带来的问题
原因:Plugin_1 没有直接使用Plugin_2的Java文件,但运行时使用了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类加载器。
Java和J2EE的类加载模型都是层次化的,只能委托给上一层类加载器;
而OSGi类加载模型则是网络图状的,可以在bundle间互相委托。——这样更合理,因为bundle间的依赖关系并不是层次化的。
优点
找不到类时的错误提示更友好。假如bundleE不存在,则bundleC就不会被解析成功,会有错误消息提示为何未能解析;而不是报错ClassNotFoundException或NoClassDefFoundError。
效率更高。
在标准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 bundle是OSGi 4引入的概念,它是一种不完整的bundle,必须要附加到一个host bundle上才能工作;fragment能够为host bundle添加类或资源,在运行时,fragment中的类会合并到host bundle的内部classpath中。
fragment有什么作用?
【场景1】bundle中有针对特定平台的代码
假设bundle对不同平台的实现方式稍有不同,Windows和Linux下代码有不同之处,即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:灵活的类加载器架构
高并发环境下死锁问题
都会锁定自己的类加载器实例。
相关推荐
了解JVM的内存模型,如堆内存(Heap)、方法区(Method Area)、栈内存(Stack)等,对于优化性能和解决内存泄漏问题至关重要。此外,理解垃圾回收的工作原理,包括分代收集、并发标记清除等策略,也是JVM调优的关键...
2. **修复内存泄漏**:使用内存分析工具,如MAT(Memory Analyzer Tool)找出内存泄漏源,并修复相关代码。 3. **调整JVM参数**:增加JVM的堆内存大小,或者调整新生代和老年代的比例,以适应应用的需求。同时,...
直接内存和堆外内存是指不在JVM堆中分配的内存,它们可以绕过JVM的内存管理,提供更高的性能,但可能导致内存泄漏。 TLAB(Thread Local Allocation Buffer)是JVM为每个线程预先分配的一小块内存,用于在堆上快速...
确保在正确的时间加载和释放资源,避免内存泄漏和其他问题。 9. **安全性与隔离**: 调用插件时要考虑安全性,防止恶意插件对主程序造成影响。使用沙箱环境或限制插件的权限是一种常见的安全策略。 10. **插件的...
4. 性能优化实践:通过技术手段对资源进行优化,包括但不限于内存管理、图片解码转移到Native层、内存泄漏的清理、主线程优先级调整等。通过框架重构、虚拟机调优等手段,达到减少GC次数和提升应用性能的目的。 5. ...
- 内存分析:介绍Eclipse内存分析工具MAT(Memory Analyzer Tool),用于检测和解决内存泄漏问题。 7. **高级主题** - SWT和JFace:解析Eclipse图形用户界面的基础——SWT和JFace库,如何创建自定义UI组件。 - ...
- **内存分析**:理解如何使用Memory Analyzer Tool (MAT) 分析和解决内存泄漏问题。 7. **团队协作** - **版本控制系统集成**:通过Eclipse与SVN、Git等版本控制系统的集成,实现代码版本管理和协同开发。 - **...
- 了解内存分析工具,监控应用内存占用,防止内存泄漏。 - 配置启动参数,调整Eclipse性能,如增加JVM内存分配。 - 使用工作台性能监视器,找出性能瓶颈。 7. **Eclipse插件推荐**: - Mylyn:任务管理工具,...
GC的主要目标是回收不再使用的对象所占用的内存,防止内存泄漏。 【类加载机制】 Java的类加载机制遵循“双亲委派模型”,即类加载器首先尝试由其父加载器加载,只有父加载器无法加载时才由当前加载器加载。自定义...
开发者需要关注内存管理,避免内存泄漏;合理使用线程,防止阻塞UI;以及利用SWT的本地化特性,提高图形渲染效率。 6. **社区与生态系统**:Eclipse RCP背后有一个庞大的开发者社区,提供了丰富的教程、文档和示例...
- **内存分析**:学习如何使用Eclipse的内置性能分析工具,进行内存泄漏检测和性能调优。 - **启动速度提升**:给出优化Eclipse启动速度和运行效率的建议。 通过本书的深入学习,读者不仅可以掌握Eclipse的基本...
这对于长时间运行的应用来说可能造成内存泄漏。 7. ClassLoader与反射: 反射API(如Class.forName())在查找类时也会涉及到ClassLoader。开发者可以指定ClassLoader来加载特定的类,这在处理动态加载或插件系统时...
- **内存分析器**:Eclipse内含性能分析工具,可以帮助识别内存泄漏和性能瓶颈。 - **启动优化**:通过调整启动配置,如减少启动插件,可以加快Eclipse的启动速度。 以上只是Eclipse开发帮助中的一小部分,实际...
书中提供了从准生产环境到测试负载设计的性能调优策略,以及系统性诊断、JVM垃圾回收监控、线程Dump分析和Mission Control工具的使用技巧,帮助开发者高效地识别和解决性能瓶颈及内存泄露等问题。 综上所述,《Java...
书中会分享一些性能调优的技巧,如何避免内存泄漏,优化启动速度,以及如何处理并发问题。 9. **案例研究**:通过实际的案例分析,读者可以更直观地了解如何将所学知识应用于实际项目中,提高解决实际问题的能力。 ...
- **测试与调试**:支持JUnit的集成测试,同时修复了一些内存泄露问题。 #### 三、JXTA安全增强 - **Alice & Bob 示例**:通过一个简单的示例解释了如何使用JXTA进行安全通信。 - **签名与验证广告**:介绍了如何对...
生命周期管理确保了插件的正确加载和卸载,防止了可能的内存泄漏或状态不一致问题。 4. **接口与通信机制**:在Engine框架中,核心应用程序与插件之间的交互依赖于定义良好的接口。这些接口定义了插件可以提供的...
- **内存安全**:通过使用智能指针和引用计数来管理内存,从而避免常见的内存泄漏问题。 - **互操作性**:可以与 C/C++ 代码交互,为跨平台移动开发提供了灵活性。 #### 六、Kotlin 新特性介绍 - **Kotlin 1.1**:...
- **AsyncTask缺陷**:AsyncTask不适合长时间运行的任务,可能会导致内存泄漏等问题。 - **设计模式**:观察者模式用于实现对象之间的解耦通知;单例模式保证一个类只有一个实例。 - **数学问题**:解决这类问题...