Java堂  


由MyEclipse内存不足谈谈JVM内存

归档在: JavaPlateform, Tools — Jet @ 3:16 下午
原文出处: http://www.javatang.com/archives/2007/12/03/1653250.html
作者: Jet Mah from Java堂
声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

如果没有进行设置的话,在使用MyEclipse的经常出现如下图所示内存不足的提示。
myeclipse.png
提示中说的很明白:“MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) space remains.”意思是说当前只有小于5%的非堆内存是空闲的。所以我们只要将这个值设置大一些就可以了。

提示中给出了设置的参数:

  1. -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M

这里有几个问题:
1. 各个参数的含义什么?
2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动?
3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置?

下面我们一一进行回答

1. 各个参数的含义什么?

参数中-vmargs的意思是设置JVM参数,所以后面的其实都是JVM的参数了,我们首先了解一下JVM内存管理的机制,然后再解释每个参数代表的含义。

  • 堆(Heap)和非堆(Non-heap)内存
    按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。
  • 堆内存分配
    JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。
  • 非堆内存分配
    JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
  • JVM内存限制(最大值)
    首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。
  • 2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动?

    通过上面对JVM内存管理的介绍我们已经了解到JVM内存包含两种:堆内存和非堆内存,另外JVM最大内存首先取决于实际的物理内存和操作系统。所以说设置VM参数导致程序无法启动主要有以下几种原因:

    1) 参数中-Xms的值大于-Xmx,或者-XX:PermSize的值大于-XX:MaxPermSize;

    2) -Xmx的值和-XX:MaxPermSize的总和超过了JVM内存的最大限制,比如当前操作系统最大内存限制,或者实际的物理内存等等。说到实际物理内存这里需要说明一点的是,如果你的内存是1024MB,但实际系统中用到的并不可能是1024MB,因为有一部分被硬件占用了。

    3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置?

    那为什么同样的参数在快捷方式或者命令行中有效而在eclipse.ini文件中是无效的呢?这是因为我们没有遵守eclipse.ini文件的设置规则:

    参数形如“项 值”这种形式,中间有空格的需要换行书写,如果值中有空格的需要用双引号包括起来。比如我们使用-vm C:\Java\jre1.6.0\bin\javaw.exe参数设置虚拟机,在eclipse.ini文件中要写成这样:

    1. -vm
    2. C:\Java\jre1.6.0\bin\javaw.exe

    按照上面所说的,最后参数在eclipse.ini中可以写成这个样子:

    1. -vmargs
    2. -Xms128M
    3. -Xmx512M
    4. -XX:PermSize=64M
    5. -XX:MaxPermSize=128M

    实际运行的结果可以通过Eclipse中“Help”-“About Eclipse SDK”窗口里面的“Configuration Details”按钮进行查看。

    另外需要说明的是,Eclipse压缩包中自带的eclipse.ini文件内容是这样的:

    1. -showsplash
    2. org.eclipse.platform
    3. --launcher.XXMaxPermSize
    4. 256m
    5. -vmargs
    6. -Xms40m
    7. -Xmx256m

    其中–launcher.XXMaxPermSize(注意最前面是两个连接线)跟-XX:MaxPermSize参数的含义基本是一样的,我觉得唯一的区别就是前者是eclipse.exe启动的时候设置的参数,而后者是eclipse所使用的JVM中的参数。其实二者设置一个就可以了,所以这里可以把–launcher.XXMaxPermSize和下一行使用#注释掉。

    参考资料:
    JDK5.0垃圾收集优化之–Don’t Pause
    提问:如何超越JVM内存限制?
    MemoryMXBean (Java 2 Platform SE 5.0)
    MyEclipse/Eclipse的内存优化与内存不足的解决办法
    eclipse.ini文件的问题
    eclipse 为什么报错

    解决dllhost占用CPU 100%的免费方法

    归档在: OS, Web&Server — Jet @ 8:52 上午
    原文出处: http://www.javatang.com/archives/2007/11/29/5253234.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    如果在Windows系统中造成CPU100%的话系统会产生延迟,反映到用所访问的站点上面就是等待的时间加长。其实是一个非常复杂的问题,但是如果是因为dllhost占用了CPU100%的话,绝大多数情况下跟IIS有关。产生这种现象的原因主要是:IIS调用ASP组件(即包括自身的也包括第三方的)的时候出现错误,比如IIS无法找到程序中所调用的组件、Access数据库损坏造成ASP操作线程死锁等等;另外一个就是可能中了冲击波病毒,这样只要找一个专杀工具就可以了,本文不在予以描述。

    因为所有的IIS组件操作在任务管理器中都是显示的dllhost.exe所占用的状况,如果想查看具体IIS中哪个部分进行操作可以通过“组件服务”来查看。在控制面板中依次打开“管理工具”-“组件服务”,然后依次选择打开“组件服务”-“计算机”-“我的电脑”-“COM+ 应用程序”,然后在上面右键选择菜单中的“查看”-“状态”,这样可以显示正在运行的组件部分。

    但是上面的操作只能粗略的查看,很多时候并不能找到出现问题的哪个部分。如果通过百度或者Google搜索的话绝大部分的文章都是提到使用某公司的产品进行监视(明显应该是软文,看来这家公司推广做的不错,呵呵),其实完全没有这个必要,下面同大家分享一下我解决问题的过程。

    如果站点中含有Access数据库文件的话首先不管三七二十一先把这些文件用Access压缩修复一下,如果还出现这个问题的话就证明不是Access数据库的问题了。

    其实只要能检测IIS执行的时间以及网址(包含参数)并记录下来,然后查看执行时间比较长的链接就是造成CPU100%的罪魁祸首。问题的关键主要是找到出现问题的链接,开始我想自己写一个ISAPI筛选器进行监视,后来无意中发现IIS自带的日志模块本身就有这个功能。右键站点然后选择“属性”打开“网址属性”对话框,在“网站”标签里面最下面选中“启用日志记录”,这里“活动日志格式”一定选择“W3C 扩展日志文件格式”,其他格式没有执行时间选项。这个时候点击右边的“属性”按钮,在“扩展属性”标签“扩展日志记录选项”中选中“URI资源”(执行操作的网址)、“URI查询”、“协议状态”、“所用时间”(后面就基于此选项的内容进行分析)这几个选项。这样记录下来的日志里面就符合我们的要求了,等到发现dellhost又出现CPU100%之后过一段时间(这是因为IIS为了提高操作效率其日志记录中含有一个操作池,只有达到设定的条件之后才会将池中的内容写入到文件中)之后就可以根据执行时间来救出造成dllhost100%的程序文件了。

    有的时候系统中不止一个地方出现问题,所以上面的方法可以重复使用。如果这样操作之后还是有问题的话那应该就是IIS自身的问题了,这个时候需要重新安装初始化IIS,具体的方法可以查看火锅城市空间的文章。另外这篇名为《关于站点程序或者ACCESS出错导致DLLHOST.exe占用CPU达100%的监测办法》的文章也值得一读。

    参考资料:
    dllhost.exe 100% cpu
    dllhost.exe CUP使用率100% 解决方法

    谈谈网络存储服务

    归档在: News&Analysis — Jet @ 4:12 下午
    原文出处: http://www.javatang.com/archives/2007/11/28/1236247.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    最近看到一篇关于Google Driver(之前叫GDriver)的消息(Google Plans Service to Store Users’ Data)。随着今年8月份微软对外正式发布其网络存储产品-Windows Live SkyDrive,人们又开始对Google Dirver这个始于2002年的项目给予了更多的关注

    其实网络存储并不是一个新鲜的词汇,说白了就是用户把本地的文件放到网络上。近年来网络存储之所以快速增长并开始火爆起来的原因在于,家庭宽带的普及和人们数字信息需求迅速的膨胀;另外网络存储最大的优势在于可以异地进行文件操作、共享等操作,非常的便捷。

    WSJ列出了目前国外主要的网络存储服务产品并做了一些比较:
    mk-am983_gdrive_20071126202132.gif

    其实国内网络存储服务的需求-无论是企业还是个人都是很大的。目前国内比较关注的两个产品就是微软的SkyDrive和Google的产品,因为这两个产品极有可能引入到进来“造福”我们。另外国内自身还有一个G宝盘(说实话,我一直记不住这个拗口的名字,呵呵)产品也是非常不错的,起步比较早,目前也积累了很多的会员。

    在技术实现方面,我觉得网络存储最大的一个难点就是大文件的上传。因为通过网络上传都是基于HTTP协议的,目前我们大多数使用的上传功能基本上都是在服务端一次性将客户端的文件读入到内存中,然后再写入到服务端磁盘上,所以上传的文件一般限制在100M以内。对于目前海量信息的时代,100M的容量实在是显得有些促襟见肘。另外对于国内而言南北线路和政府政策的问题也很关键。

    综合来看,对于网络存储的各种需求使得这个领域的前景非常光明,目前市面上的网络存储产品功能都显得过于简单和单一,像用户和文件权限、安全性都显得很单薄,我们期待Google Driver能不能像GMail刚推出时的那样给我们更多的震撼。

    参考资料:
    Reheated GDrive rumors surface
    网络存储梅开二度

    让WindowsXP中的IIS支持多站点的工具

    归档在: OS, Tools — Jet @ 4:48 下午
    Tags: ,
    原文出处: http://www.javatang.com/archives/2007/11/19/4845244.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    众所周知,在XP professional中使用IIS不能创建多个站点,虽然我们可以使用“虚拟目录”来调试程序,但有很多时候并不方便。今天无意中发现一个可以创建多站点的工具-IISAdmin,下载地址:http://www.firstserved.net/download/iisadmin.zip

    程序非常简单,界面如下:
    iisadminfull.gif
    使用“create”创建一个新的站点,可以设置站点描述、端口号以及站点的位置。软件没有设置“编辑”功能,如果需要对站点进行编辑处理的话可以使用IIS进行编辑,这个时候打开IIS之后会发现刚才创建的所有的站点都已经显示在列表中了。

    点击软件中的“start”可以启动选中的站点,细心的朋友可以注意到的是每次只能启动一个站点。如果我们在IIS中同时启动两个站点的话会出现一个“不支持请求”的错误提示。所以这个软件很巧妙的解决了在XP中IIS不能创建多个站点的问题(这一点应该是被IIS所屏蔽了),但没有从根本上解决同时启动多个站点的问题,我想这个应该是XP系统底层对IIS进行的限制,基本无法突破。不过这样对于我们调试程序来说已经足够了。

    软件同时还可以了重新启动IIS的功能,其实是调用了软件中所包含的iisreset程序,类似于iis6中自带的功能,非常的方便。软件还支持Windows 2000 Professional和Windows Vista Business系统。

    最后需要注意的一点是如果使用IISAdmin删除一个正在运行的站点,则如果再启动另外一个站点的时候会出现如下的错误:
    iisadmin_error.png
    这个时候IIS中所有站点也会出现红色的图标,无论做任何操作都是提示“不支持请求”。这个应该是软件的一个bug,解决的办法是重启一下IIS就可以了。

    非常好的服务器备份软件 - Acronis True Image Server

    归档在: Tools, Web&Server — Jet @ 4:58 上午
    原文出处: http://www.javatang.com/archives/2007/11/16/5809241.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    服务器备份是非常重要的,特别对于应用于商用的数据。当然备份的方式有很多种,但是我觉得最简单而且有效的一种方式就是增加一块新的硬盘最为备份硬盘,然后使用程序将特定的数据根据频率备份到该硬盘上面,这样即使其中有一块硬盘出现问题依然可以保证数据的完整性。

    上面的方案中一款优秀的备份软件是非常重要的,Acronis True Image Server是一个非常棒的选择。这款软件不仅仅可以备份某个磁盘分区,而且还可以备份指定的文件或目录,另外最主要的是它还支持备份任务功能,这样可以设定某个频率来备份指定的数据,非常的强大和方便。

    acronis_true_image.png

    软件的使用也非常简单,全部采用向导式的操作方式。另外软件有Windows和Linux两个版本,可以在http://www.verycd.com/topics/78520/下载。

    两个PHP的Warning及解决方法

    归档在: DynamicLanguage — Jet @ 5:56 下午
    Tags:
    原文出处: http://www.javatang.com/archives/2007/11/11/5611239.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    1. Cannot modify header information

    PHP Warning: Cannot modify header information - headers already sent by (output started at yourfiles)

    这是因为设置的头文件信息溢出造成的。解决方法:将output_buffering 设为 on 就可以了

    2. output handler ‘ob_gzhandler’ conflicts with ‘zlib output compression’

    PHP Warning: ob_start() [ref.outcontrol]: output handler ‘ob_gzhandler’ conflicts with ‘zlib output compression’ in yourfiles

    这是因为PHP中Zlib模块设置错误造成的,将zlib.output_compression这一行注释掉就可以了。这里需要指出的是PHP5自带GZIP模块的,不需要另外加载。

    参考资料:
    解决Warning: Cannot modify header information - headers already sent by ……
    启用页面 Gzip 压缩后发生错误,请指点

    “终端服务超出最大允许连接数”问题产生原因及解决方法

    归档在: OS — Jet @ 3:01 下午
    原文出处: http://www.javatang.com/archives/2007/11/02/0146237.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    在客户端远程登录Windows2000/2003服务器的时候,有时会出现“终端服务超出最大允许连接数”的提示,然后远程登录关闭。造成该提示的原因是在Windows2000/2003中系统默认设置了最大允许远程连接的数量,如果每次连接后没有使用“注销”命令退出而是直接关闭窗口的话就会造成上面的连接依然保持,这样时间一长就会造成远程连接的数量超过了最大连接的数量,最后产生上面的错误提示。

    解决的方法如下:如果已经出现该错误另外系统没有设置连接超时时间的话只能通知机房重启一下服务器了;如果设置了超时时间(后面我们会详细说明如何设置)则可以等过了设置的超时时间之后再连接就可以了。

    防止产生该错误需要注意以下几点:

    1. 每次退出连接的时候务必使用“注销”命令而不是直接关闭连接窗口,这一点非常重要!

    2. 修改最大连接的数量以及设置结束断开连接的会话时间。前者可以设置一个最大连接的数值从而达到一个较多的范围,但通常来说不宜设置很大的数值;后者可以在非正常情况下断开连接之后,系统过一段时间自动断开该连接。

    修改最大连接数的方法是:打开“终端服务配置”管理项(可以在运行中输入“tscc.msc”,也可以在控制面板的“管理工具”中打开“终端服务配置”链接),选择“连接”,然后双击打开右边的“RDP-Tcp”项,在“会话”标签中选择最上面的第一个“替代用户设置”,然后设置“结束已断开的会话”一个时间,比如15分钟,这样非正常断开的会话会在15分钟之后自动断开而不占用连接。

    顺便说一句,下面的“活动会话限制”是指每次远程连接的时间,建议使用默认;“空虚会话限制”是指如果在远程连接中没有任何操作之后多长时间自动断开连接,如果你的远程连接开着然后你有事情离开电脑了,系统会自动在默认时间内断开连接,从而保证了安全。不过有的时候我们开着远程连接临时在本机查阅其他资料,有时远程连接会很“聪明”地断开,这点很讨厌,可以根据自己的实际需求在这里设置一个时间,同时可以选中第二个“替代用户设置”,然后设置达到上述限制之后直接结束会话。

    可以使用下面的操作设置结束断开连接的会话时间:Windows2003中可以打开“组策略”管理项(可以在“开始”-“运行”中输入“gpedit.msc”,也可以在控制面板的“管理工具”中打开“组策略”链接),依次打开“计算机配置”-“管理模板”-“Windows组件”-“终端服务”,然后双击打开右边的“限制连接数量”项,选择“已启用”然后设置一个数值,这里建议不要超过10。Windows2000中没有上面的策略项,可以在上面修改最大连接数的方法中打开的“RDP-Tcp属性”对话框中的“网卡”标签中设置。

    需要特别注意的是,上面的所有更改对于当前的这次远程连接是无效的。

    3. 如果是Windows2003系统的话,可以强制每个帐户使用一个会话,这样如果断开重新连接的时候会接着前面断开的连接。设置方法是:打开“终端服务配置”管理项(具体方法见上),在“服务器配置”中启用“限制每个用户使用一个会话”。

    另外如果前面的连接非正常中断,等到重新连接之后可以手动将前面断开的连接注销掉。打开命令行窗口,输入query user查询当前连接服务器的用户,然后使用 logoff #id注销断开的连接。

    举例如下:

    C:\Documents and Settings\user1>query user
    USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
    >user1 rdp-tcp#6 5 运行中 . 2007-11-2 10:21
    >user1 rdp-tcp#7 6 . 2007-11-2 11:05
    C:\Documents and Settings\user1>logoff 6

    C:\Documents and Settings\user1>query user
    USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
    >user1 rdp-tcp#6 5 运行中 . 2007-11-2 10:21

    如果是在Windows2003中操作更直观,在“任务管理器”中的“用户”标签中会直接显示当前连接的用户情况,右键选中的用户可以对其进行注销操作。

    参考资料:
    解决Windows 2000 Windows 2003终端服务器超出最大允许链接数的问题

    Visual C++ 6.0中error LNK2001和error C2065问题的解决方法

    归档在: C++Plateform — Jet @ 3:43 上午
    原文出处: http://www.javatang.com/archives/2007/11/01/4346235.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    1. error C2065错误:错误描述类似于下面的文字:

    error C2065: ‘timeGetTime’ : undeclared identifier

    这是因为没有包含头文件而导致编译器找不到所使用的函数,只要查阅MSDN将对应的头文件include进去就可以了。

    1. #include <mmsystem.h>

    2. LNK2001错误:错误描述类似于下面:

    error LNK2001: unresolved external symbol_…

    这是因为没有链接对应的lib文件造成的,在#include语句之前加入#pragma语句,比如:

    1. #pragma comment(lib, "Ws2_32.lib")

    总之需要根据MSDN中的“Requirements”所要求的header和lib使用上述方法添加到程序头文件中即可。

    参考资料:
    郁闷的error LNK2001: unresolved external symbol,请大家帮忙..
    error LNK2001: unresolved external symbol _main解决办法
    MFC开发求助

    C++基础之字符串处理函数

    归档在: C++Plateform — Jet @ 10:20 上午
    Tags:
    原文出处: http://www.javatang.com/archives/2007/10/30/2016233.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    Strlen()用来计算字符串的长度,其中并不包含结束字符。此函数会计算字符串的字节长,不把结束字符算在内。

    Strcpy()是将一个字符串复制到另一个字符串。若要将字符串s2复制到字符串s1中,则s1必须要有足够的空间来容纳s2,最后此函数返回s1的起始地址。

    Strcat()是将两个字符串合并成一个字符串。若要将字符串s2连接到字符串s1的后面,则必须将s1的结束字符去掉,且字符串s1要有足够的空间来容纳字符串s2,最后此函数返回s1的起始地址。

    CString.Format 用于格式化数字从而将其转换为CString类型,示例代码如下:

    1. CString str;  
    2. int num = 20;  
    3. str.Format("%d",   num);

    参考资料:将数字转换为字符串用哪个函数.

    用js检测是否安装指定插件的函数

    归档在: DynamicLanguage — Jet @ 12:27 下午
    Tags:
    原文出处: http://www.javatang.com/archives/2007/10/28/2751231.html
    作者: Jet Mah from Java堂
    声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

    最近需要实在使用Javascript来检测客户端是否安装Quicktime插件,但是网上都是一些用来检测是否安装Flash插件的例子,而且大多数都是针对于IE的,后来查阅了一些例子然后写了一个用来检测任何插件的通用函数,现在拿出来同大家分享。

    1. /*
    2. * 用来检测是否安装指定的插件
    3. * pluginsName 插件的名称
    4. * activexObjectName 控件名称,主要针对于IE
    5. * author: Jet Mah
    6. * website: http://www.javatang.com/archives/2006/09/13/442864.html 
    7. */ 
    8. function checkPlugins(pluginsName, activexObjectName) {
    9.     // 通常ActiveXObject的对象名称是两个插件名称的组合
    10.     if (activexObjectName == '') activexObjectName = pluginsName + "." + pluginsName;
    11.    
    12.     var np = navigator.plugins;
    13.     // 针对于FF等非IE
    14.     if (np && np.length) {
    15.         for(var i = 0; i < np.length; i ++) {
    16.             if(np[i].name.indexOf(pluginsName) != -1) return true;
    17.         }
    18.         return false;
    19.     }
    20.     // 针对于IE
    21.     else if (window.ActiveXObject) {
    22.         try {
    23.             var axobj =eval("new ActiveXObject(activexObjectName);");
    24.             // 将对象转化为布尔类型
    25.             return axobj ? true : false;
    26.         } catch (e) {
    27.             return false;
    28.         }
    29.     } else {
    30.         // 以上情况都排除则返回false
    31.         return false;
    32.     }
    33. }

    最后说明一点的是,如何来查找插件的名称?我是通过Editplus中Html工具栏里面的“插入Object”命令来获取的,比如插入Flash对象之后这个命令会产生一段HTML代码,其中Object中的id属性里面,将名称的空格和最后的Object去除就是对象的名称了。比如Flash的id为“Shockwave Flash Object”,那它的插件名称为“Shockwave”;Quicktime的插件名称为“Quicktime”等等。

    参考资料:
    JavaScript 判断是否安装了 Flash 插件

    « 上一页下一页 »