项目中遇到的JVM难点
——启动OSGi容器时,出现永久代内存不够。内存泄露
——OSGi找不到类路径问题。
——线程死锁问题。
问题一:OSGi类内存问题
其次,从内存用量来看,OSGi允许不同版本的Package同时存在,这是个优点,但是客观上会占用更多内存。例如,一个库可能需要 ASM 3.0,而同一应用程序使用的另一个库可能需要ASM 2.0,要解决这种问题,通常需要更改代码,而在OSGi中只需要付出一点Java方法区的内存即可解决。
不过,如果对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:灵活的类加载器架构
P279
高并发环境下死锁问题
都会锁定自己的类加载器实例。
- OSGi类加载流程
思路 OSGi每个模块都有自己独立的classpath.如何实现这一点呢?是因为OSGi采取了不同的类加载机制: OSGi为每个bundle提供一个类加载器,该加载器能够看到bundle Jar文件内 ...
- JVM,Tomcat与OSGi类加载机制比较
首先一个思维导图来看下Tomcat的类加载机制和JVM类加载机制的过程 类加载 在JVM中并不是一次性把所有的文件都加载到,而是一步一步的,按照需要来加载. 比如JVM启动时,会通过不同的类加载器加载 ...
- 并行类加载与OSGI类加载
这回来分析一下OSGI的类加载机制. 先说一下OSGI能解决什么问题吧. 记得在上家公司的时候,经常参与上线.上线一般都是增加了一些功能或者修改了一些功能,然后将所有的代码重新部署.过程中要将之前的服 ...
- OSGi 对软件复杂度的影响
出自 深度理解 osgi equinox 原理 1.2.1 OSGi 能让软件开发变得更容易吗 不可否认,OSGi 的入门门槛在 Java 众多技术中算是比较高的,相对陡峭的学习曲线会 为第一次使用 ...
- OSGi解决的问题
osgi最明显的缺陷 bundle尽管可以为隔离的服务建立独立生命周期管理的热部署方式,以及明确的服务导出和导入依赖能力,但是其最终基于jvm,无法对bundle对应的服务实现计算资源的隔离,一个服务 ...
- Springboot Application 集成 OSGI 框架开发
内容来源:https://www.ibm.com/developerworks/cn/java/j-springboot-application-integrated-osgi-framework-d ...
- 深入理解OSGI:Java模块化之路
简介 Java可能是近20年来最成功的开发技术,因其具备通用性.高效性.平台移植性和安全性而成为不同硬件平台理想的开发工具.从笔记本电脑到数据中心,从游戏控制台到科学超级计算机,从手机到互联网,Jav ...
- 深入理解JVM(一)类加载器部分、类变量、常量、jvm参数
类加载概述 在java代码中,类型的加载.连接与初始化过程都是在程序运行期间完成的 类型:class.interface(object本身).类型可在运行期间生成,如动态代理.一种runting概念 ...
- 深入理解jvm-2Edition-虚拟机类加载机制
1.概述-什么是类加载? 将Class文件从其他地方(外存.字节流甚至是网络流中)载入内存, 并对其中数据进行校验.转换解析和初始化,最终从其中提取出能够被虚拟机使用的Java类型. 用图纸造模子,该 ...
随机推荐
- CSS3 Flex布局(容器)
一.flex-direction属性 row(默认值):主轴为水平方向,起点在左端. row-reverse:主轴为水平方向,起点在右端. column:主轴为垂直方向,起点在上沿. column-r ...
- python函数回顾:dict()
描述 dict() 函数用于创建一个字典. 语法 dict 语法: class dict(**kwarg) class dict(mapping, **kwarg) class dict(iterab ...
- [Erlang危机](5.1.3)进程
原创文章,转载请注明出处:server非业余研究http://blog.csdn.net/erlib 作者Sunface 联系邮箱:cto@188.com Processes Trying to ge ...
- 卷积神经网络(CNN)的训练及代码实现
本文部分内容来自zouxy09的博客.谢谢.http://blog.csdn.net/zouxy09/article/details/9993371 以及斯坦福大学深度学习教程:http://ufld ...
- mongodb文档支持的数据类型
版权声明:转载请标明来源. https://blog.csdn.net/u014285882/article/details/25510377 1. 存储类型 mongodb文档相似于json,但不是 ...
- Android-实现切换Fragment页功能
场景:使用Fragment实现切页. 类结构: 一:Activity Activity中使用getSupportFragmentManager().beginTransaction()来填充一个Fra ...
- windows安装pywin32
下载旧版 https://sourceforge.net/projects/pywin32/files/pywin32/ 下载新版 https://github.com/mhammond/pywin3 ...
- Python之 Django 初级
Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...
- iOS 关于自动更新的分阶段发布(灰度发布)的相关简介
前言: AppStore 发布应用方式除了自动和手动,如今添加了分阶段发布(灰度发布).目的很明确,降低新版本骤然上升的bug率,不能挽回,只能发布新版本的风险.也也是针对禁止使用热修复,推出的相对 ...
- java配置好jdk-bash: /usr/bin/java: No such file or directory
在 Linux 系统中安装 JDK 环境,配置好环境变量后,输入 java.javac 或者 java -version 等时,都提示如下错误: -bash: /usr/local/java/bin/ ...