存档

2009年8月 的存档

IBM JDK的Java堆空间的碎片问题

2009年8月13日 hashei 1 条评论

IBM的JDK容易产生堆碎片的问题,在这篇中我也有牵涉到,今天再次看到,就拿出来老生常谈一下,顺便内容扩充一下。本文大部分内容参考

【IBM内存碎片类问题,不可不看】JVM申请内存失败并频繁GC问题的分析思路

问题描述

通常情况下,对于Java虚拟机出现,只需要配置heap最大最小值,以及maxPermSize,但是这种情况仅限于SUN的Java虚拟机。对于IBM的JVM,情况就完全不一样。

对于Sun的JVM来说,它的GC策略默认是复制、分代算法。也就是说,它会将heap分成不同的几个区,譬如Solaris JVM中最上面有两个大小相等的区。GC时刻,将一个区的存活对象复制到另外一个对等区,垃圾对象就算遗弃了。这样在heap里面,就不存在碎片问题。另外Sun的JVM有单独的方法区,也就是Permanent Generation,方法区中保存的一般是Class对象,而不是普通的实例对象,也就是JVM的元数据。

IBM的JVM默认GC策略并没有采取复制、分代。这个可以从GC日志分析出来。它不像Sun的JVM那样,有个单独的方法区,它的方法区就放在Java Heap里面。在IBM的JVM里面,这些对象一般分配在称为k-cluster和p-cluster里(cluster又是属于Heap),而后者一般是临时在heap里面申请。并且,这些cluster是不能GC,或是被移动重排的(Compact过程)。这就导致Java Heap里面就如同蜂窝,但不同的蜂孔又不能合并,于是,当我们程序里面产生一个大对象,譬如2M的数组(数组必须分配在连续的内存区)时,就没有可分配空间了,于是就报告OOM。这些不能被移动的cluster之间的空隙就称为所谓的碎片。此时,JVM的Heap利用率可能不到50%。

k-cluster能够存放1280个类对象,第一个p-cluster大小为16K,默认存放类似于JNI对象和线程对象等不能移动的对象(pinned),然后k-cluster中存放不下的类对象也会放在p-cluster中,第一个p-cluster满了之后,后续的p-cluster大小只有2K,一个类对象大小是256字节

举一个例子

假设我们的系统一共要生成11280个类对象(可能没这么多class,但是同一个class由不同的classloader加载的话,尤其是使用了Spring、Hibernate这些框架的情况下,这些框架经常通过反射创建实例,所以导致Class对象的数量大大增加),那么除了k簇中存放的1280个之外,其余10000个要放到p簇中。假设初始的16k的p簇中存放的完全是线程和JNI对象,也就是说我们的类对象要用后来申请的2k一个的p簇来存放。

那么一共需要 10000*256/2048  ==1250个p簇

假设我们的堆大小为1G,那么堆内碎片的平均大小是1G/1250,也就是不到1M。这个时候你申请1M以上的内存,就有很大的可能会遇到碎片问题造成的AF。

解决方法

对于IBM的JDK,设置恰当的最大堆和最小堆,设置-Xk和-Xp避免碎片问题,如果程序需要分配大对象较多,那么调整一下LOA的大小(判断标准是gc日志里大量AF是由于分配大于64K内容而产生的,gc日志的分析方法可以看这篇)。

参考参数:-Xk22000 -Xp64k,16K -Xloratio0.2(注意X都为大写)

对于1.5之后的JDK,如果采用默认的optthruput策略或者optavgpause策略,那么也是要设置-Xk和-Xp避免碎片问题,对于gencon策略,因为是分代回收的方式,理论不需要设置-xk -xp参数了,但是IBM没有独立的Permanent Generation,所以一切的调整还是要根据gc日志来。

Avoiding Java heap fragmentation with Java SDK V1.4.2. 翻译版

如何在IBM JDK 1.4.2的环境中避免Java堆空间的碎片问题
内容提要:
用户在使用WebSphere Application Server(以下简称WAS)运行自己应用的时候经常会碰到Out Of Memory的问题(简称OOM问题),其中很大一部分的情况是Java堆空间碎片问题引起的OOM问题。IBM JDK 1.4.2的版本中JDK对GC的行为做出了一定的改进。其中一些JDK参数的引进可以改善Java堆空间的碎片问题。
本文首先会给出IBM JDK 1.4.2中对于K簇(k-cluster)和P簇(p-cluster)工作模式的解释。然后在此基础上介绍JDK 1.4.2为解决碎片问题采取的新算法。最后,给出WAS中为改善Java堆空间碎片问题使用的JDK运行参数。
正文:
一、K簇和P簇
在Java堆空间中分配的内存对象通常是可以移动,如果垃圾回收程序(garbage collector)决定重新序列化堆空间的时候,可以四处移动这些对象。然而,有些对象永远或者临时无法移动。这些固定不动的对象就是常说的pin对象(pinned object)。
在IBM JDK 1.4.2中,垃圾回收程序首先会分配一个K簇作为堆空间底部的第一个对象。K簇是专门用来存储“类块”(class block)的区域。K簇可以容纳1280个类块条目。每个类块的大小是256个字节。紧接着垃圾回收程序会分配一个P簇作为堆空间中的第2个对象。P簇是用来存储pin对象的区域。第一个P簇的默认大小为16KB。
当K簇满了的情况下,垃圾回收程序在P簇中继续分配类块。当P簇满了的情况下,垃圾回收程序会分配一个大小为2KB的新P簇。由于这些新的P簇可以被分配到任何地方而且又不能被移动,这就造成了碎片的问题。
二、pinnedFreeList算法
为了解决这些问题,IBM JDK 1.4.2版本中起用了pinnedFreeList来改变P簇的分配方法。方法的关键是在每一次GC(garbage collection)后,垃圾回收程序从未分配列表的底部分配一些存储区并把它们串到pinnedFreeList上。分配P簇的请求将从pinnedFreeList分配空间,而其他分配内存的请求将从堆的未分配列表上分配。无论堆的未分配列表或者pinnedFreeList被耗尽,垃圾回收程序都会造成一次分配失败并且引起GC。这种方法确保所有的P簇被分配在堆空间尽可能低的位置。
垃圾回收程序按照如下的算法确定给pinnedFreeList分配多少存储空间:
●        初始分配的空间是50KB
●        如果不是初始分配并且pinnedFreeList为空,那么垃圾回收程序会比较50KB和从上一次GC到现在总共分配P簇大小5倍的数值,按照较大的数值分配
●        如果不是初始分配并且pinnedFreeList不为空,那么垃圾回收程序会比较P簇溢出设定值(默认为2K)和从上一次GC到现在总共分配P簇大小5倍的数值,按照较大的数值分配
这一算法在应用需要加载很多类的情况下会增大pinnedFreeList的大小。这样可以避免由于pinnedFreeList耗尽引起的分配失败。同时算法在分配很少P簇的情况下会减少pinnedFreeList的大小。这样可以避免pinnedFreeList占用过多的堆空间。
buildPinnedFreeList函数利用上面的算法构建pinnedFreeList。这个函数在如下地方会被调用:
●        在初始化簇(initializeClusters)时
●        在堆空间扩展(expandHeap)结束时
●        在gc0_locked结束时
垃圾回收程序通过调用nextPinnedCluster函数在pinnedFreeList中分配P簇。这个函数的工作方式类似于nextTLH工作方式:总是从pinnedFreeList获取下一个空的块。如果pinnedFreeList空了,会产生manageAllocFailure。
在realObjCAlloc里,如果在P簇中没有空间了,垃圾回收程序就会调用nextPinnedCluster函数分配一个新的P簇。
在初始化簇(initializeClusters)时,垃圾回收程序调用nextPinnedCluster,nextPinnedCluster会分配一个50K大小的初始P簇,因为pinnedFreeList中唯一的空余块的大小是50K。空余块的大小等于50K是因为pinnedFreeList在初始状态下被设置为50K。
三、调整Java运行参数
对于一个大的Java应用,比如:WAS,默认的K簇可能不足以分配所有的类块。在IBM JDK 1.4.2版本中,可以通过使用-Xk和-Xp命令行参数来设定K簇和P簇的大小,例如:
-Xknnnn
其中nnnn代表K簇中可以容纳的类块的最大数目。通过添加Java的运行是参数-Dibm.dg.trc.print=st_verify  可以在GC的详细信息中得到合适nnnn的值,例如:
<GC(VFY-SUM): pinned=4265(classes=3955/freeclasses=0) dosed=10388 movable=1233792 free=5658>
pinned和classes的数值可以为-Xk的正确数值提供参考。一般推荐使用classes(3955)数值的110%左右,所以在这个例子中-Xk4200是一个合适的设置。
尽管,pinned和classes的数值之间的差值给pCluster的初始大小提供了线索。但是,因为每一个对象可能有不同的大小,所以很难预测P簇所需要的大小和P簇溢出的大小。用户可以通过-Xp命令行参数-Xp设定P簇的初始大小和溢出大小。例如:
-Xpiiii[K][,oooo[K]]
其中,iiii代表P簇的初始大小,单位是KB,oooo是可选的,代表溢出P簇(后续的P簇)的大小。iiii和oooo的默认值为16KB和2KB。
如果用户的应用确实遇到了堆空间碎片的问题,可以考虑打开GC的详细信息并使用-Dibm.dg.trc.print=st_verify参数,并从分析值中得到合适的-Xk值。如果问题依旧存在,可以考虑试验加大P簇的初始大小和溢出大小。

另,从1.3.1 SR7之后的JVM版本,就能使用-Xp -Xk参数了,JVM的版本可以通过java -version或者systemout.log每次启动开头看到

Because this new pCluster can be allocated anywhere in the heap and must be pinned, it can cause fragmentation problems. The pinned objects effectively deny the GC the ability to combine free space during heap compaction and could result in a heap that contains a lot of free space but in relatively small discrete amounts, so that an allocation that appears to be well below the total free heap space will fail. To solve this problem, release 1.3.1 at SR7, and later, provides command-line options to specify the kCluster (-Xk), pCluster (-Xp) and pCluster overflowsize (-Xp). Use these options to set the initial sizes of the ’clusters’ to be large enough to avoid fragmentation issues.

【每周精华】第五期(7月20日-8月10日)

2009年8月10日 hashei 没有评论

[1]SQL Server 索引结构及其使用

数据查询的快慢往往影响着一个应用的生与死。这个系列4篇文章是针对SQL Server的索引结构,介绍了聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)的区别,使用的环境、策略,并比较了不同索引策略造成的不同结果。对于书中的一些说法,文章也通过实验给出了不同的看法。

下面的表总结了何时使用聚集索引或非聚集索引(很重要):

动作描述 使用聚集索引 使用非聚集索引
列经常被分组排序
返回某范围内的数据 不应
一个或极少不同值 不应 不应
小数目的不同值 不应
大数目的不同值 不应
频繁更新的列 不应
外键列
主键列
频繁修改索引列 不应

第一篇 http://www.vckbase.com/document/viewdoc/?id=1307

第二篇 http://www.vckbase.com/document/viewdoc/?id=1308

第三篇 http://www.vckbase.com/document/viewdoc/?id=1309

第四篇 http://www.vckbase.com/document/viewdoc/?id=1310

[2] 一个RoR的站点性能优化的故事

俗话说:是骡子是马,拉出来溜溜。压力低的应用,客户有钱买硬件,那随便你怎么折腾都没关系。不过面对日上百万PV的web2.0站点,优化的能力就不可小觑,优秀的开发团队还是拙劣的队伍立分高下。

虽然你我也许没有遇到这样的情况,但是就算当故事书来读,也是很有趣的。

http://ityum.net/2009/08/01/00/02/一个ror的站点性能优化的故事.html (原站MS无法打开了)

暂时google了一个 http://blog.donews.com/chinaz/archive/2009/08/04/1546463.aspx

[3] 互联网草根的故事

互联网大佬的故事往往让人汹涌澎湃却也望之兴叹,于是草根站长的故事就平易近人的多。不过虽说草根,也不是睡个觉就能数钱的。考实力还是搏出位,背后还都离不了“偏执”在里头。

 蔡文胜 李兴平从竞争到合作 共铸站长之王

注册Weblogic9为Windows服务及外一篇

2009年8月7日 hashei 6 条评论

Weblogic8时代将weblogic注册成为Windows服务是一件很简单的事,只要执行Domain目录下的installService.cmd即可。不过进入Weblogic9之后,domain目录下就没有了那个脚本,而是出现在%WL_HOME%/server/bin下,直接运行会生成一个“bea _”的服务,运行的话。。。没有任何结果,BEA的edocs上也没有找到有用的帮助。

以下内容,是我盯着installService.cmd和startWeblogic.cmd出神良久后试验成功的。

  1. 复制一份installServer.cmd到domain目录下,
  2. 编辑installServer.cmd,在set WL_HOME=……   下添加set DOMAIN_HOME=<你的domain目录>
  3. 将下一行的call “%WL_HOME%\common\bin\commEnv.cmd”修改成call “%DOMAIN_HOME%\bin\setDomainEnv.cmd”(如果这里的setDomainEnv.cmd写完整路径,那么上一步DOMAIN_HOME可以不用设置,因为setDomainEnv.cmd里还会声明一遍的)
  4. 另起一行,添加两行“set USERDOMAIN_HOME=%DOMAIN_HOME%”“set DOMAIN_NAME=<你的domain名字>”(这是脚本最末一段Install the service里beasvc命令所需要的参数)
  5. 运行installServer.cmd,会在服务里新建一个名为“beasvc %DOMAIN_NAME%_%SERVER_NAME%”的服务,自动运行,帐户属性的是localsystem。

beasvc命令各个参数的详细意义可以参考beasvc /help

以上内容对于Oracle Weblogic 10依旧有效。

weblogic密码遗忘补救方法

  1. 备份   %DOMAIN_HOME%/security下的DefaultAuthenticatorInit.ldift文件,和%DOMAIN_HOME%下的boot.properties文件(如果不在这个目录,那么找找 %DOMAIN_HOME%/servers/AdminServer/security目录),这样如果下列步骤操作失败还能还原回去。
  2.   运行java -cp /bea/weblogic92/server/lib/weblogic.jar weblogic.security.utils.AdminAccount <新用户名> <新密码> .(注意最后有个点的,点之前有空格,不要和原先的一样)
  3. 执行完后在当前目录会生成一个新的DefaultAuthenticatorInit.ldift文件,然后替换原来的%DOMAIN_HOME%/security/DefaultAuthenticatorInit.ldift文件。
  4. 从%DOMAIN_HOME%/servers/AdminServer/data/ldap/子目录中删除初始化状态文件DefaultAuthenticatormyrealmInit.initialized,删除boot.properties。
  5. 运行startWebLogic.sh,启动过程中会让你输入用户名和密码,输入新建立的那个
  6. 用新的用户名密码登录管理控制台,在“安全领域”里点击“myrealm”,在用户和组里,找到之前的那个用户,修改密码,保存,那么以后可以继续使用原来的用户名和密码登录,
  7. 修改boot.properties中的用户密码为上一步修改过的用户密码(明文)格式为
    username=用户名
    password=密码
  8. 重启服务器,现在不用输入用户名密码了,成功启动后,weblogic会加密用户密码的,现在就可以用旧用户登录,新用户可以删除。

家庭无线网络简明安全指南

2009年8月4日 hashei 1 条评论

上周表妹让我帮忙买个无线路由器,为的是能在两个房间都能上网。这年头家里有两台电脑的越来越多,加上带wifi功能的手机、NDSI、Wii等娱乐设备,不管是电信还是网通给的ADSL猫都没有多余的口再来插网线了,而且如今无线路由器只要120就能搞定54M速率的,所以大家都开始wireless了。

不过我在家直接用笔记本搜索到的无线情况如下:在一共搜索到的7个无线节点中,有1个没有采用任何的加密措施,可以直接连接上。

wireless no security

而且路由器启用了DHCP,我毫不费力的得到了一个IP地址192.168.1.100,通过这个IP地址,那么默认的路由器ip就是192.168.1.1了。

tplink admin

TP-LINK的路由器,默认用户名、密码是admin/admin,别的品牌默认密码不外乎password、changeme(话说回来,这种人人皆知的也不好叫密码了),顺利进入。

看来这个路由器买回来唯一做过的就是按着配置指南,step by step的输入了ADSL的账号,可以打开路由器时自动连接。除此之外,就是一座不设防的空城。

通过上述“入侵”的过程,你也许对如何加强安全性有点头目了:

  1. 隐藏SSID号
    SSID(Service Set Identifier)也可以写为ESSID,用来区分不同的网络,最多可以有32个字符,无线网卡设置了不同的SSID就可以进入不同网络,SSID通常由AP广播出来,通过XP自带的扫描功能可以相看当前区域内的SSID。出于安全考虑可以不广播SSID,此时用户就要手工设置SSID才能进入相应的网络。简单说,SSID就是一个无线局域网的名称,只有设置为名称相同SSID的值的电脑才能够连接到同一个无线网络中互相通信。
  2. 设置非默认管理端口和复杂密码
    不要使用192.168.X.1的管理端口和admin、admin这样的密码
    别人都总结的好好的了 http://www.phpv.net/html/1553.html
  3. 禁用DHCP
    别一下网段、网关什么的都暴露了
  4. MAC地址过滤
    只允许自己的网卡访问路由,其它一概禁止

以上这些,只要您打开路由器的配置界面,从上到下,每一项都点一遍,就知道在哪里设置了。不过这些“雕虫小技”,除了最后一项会对入侵者设置一些障碍(可以通过伪造mac地址破解),其它的操作只防得了君子,对小人是一点用都没有的。要想把小人赶出门外,只能用加密措施。

security key

 security option

security methord

安全类型选择WPA/WPA2,安全选项选择WPA2,加密方法选择AES,这三者是现在最安全的无线网络设置组合。

为什么不要选择WEP的加密方式?

Wired Equivalent Privacy (WEP)的工作原理是用RC4流密码方式用密钥对密文进行安位异或生成密文进行加密。流密码使用的要点就是密钥不能重复,要保证完全的随机性。WEP使用用户设置的密码和一个24bit的初始向量来作为输入的密钥,这样虽然达到了64位(10个十六位进制数*4+24,记得你在连接路由器时输入的10位密码么)或者128位(26个十六进制数*4+24)的加密强度。但是真正随机的只有那24位,我想没几个人会一直修改无线路由的连接密码吧。

这样导致的后果就是入侵者可以先忽视你那“永远不变”的40位或者104位,学名叫“相关密钥攻击(Related-key attack)”,24位的穷举可能性不过16777216种。利用生日悖论,每4096个网络包就可能共享同一个初始向量,从而导致一样的RC4密钥。

有了以上理论基础,网络嗅探工具加上暴力破解工具有了用武之地。按照下面几个帖子里的内容,平均10分钟就可以破解出使用WEP加密方法的密码。

BackTrack 使用全解

XP系统里利用VMware虚拟机启动BT3破解无线WEP和WPA傻瓜版教程

Intel3945ABG在BT3下破解有(无)客户端wep简明教程

WPA用Temporary Key Integrity Protocol (TKIP)机制避免了WEP的这个重大缺陷,一般支持WEP的无线网卡和路由都能支持WPA。当然更安全的是WPA2加密协议,使用AES来代替TKIP。至于WPA-PSK则是WPA Personal的缩写,一般家庭使用,而WPA Enterprise顾名思义适合企业用户使用。如果你的无线路由器或网卡不支持WPA2,那么试试升级firmware或者驱动,实在不行使用WPA,千万不要再使用WEP了。

参考文章 http://arstechnica.com/security/news/2008/04/wireless-security.ars

分类: 信息安全 标签: , , ,