技术掘金 - 编程开发
type: channel
link: http://blog.guqiankun.com/category/develop/
items: 存储与文件系统
items: 字符集与编码
items: Smobiler分析对比
items: 高并发场景下System.currentTimeMillis()的性能优化
items: 验证和授权
items: 设计简单的后台管理的数据排序
items: JSP与MySQL交互的中文乱码解决方案及总结
items: catalana.bat详解
items: tomcat的JVM设置和连接数设置
items: 详解Tomcat配置JVM参数步骤

存储与文件系统
type: item
date: 2020-09-16T14:53:00+08:00
description: 存储 (Storage)存储是用于保有数据的技术。目前计算机存储采用的技术方式主要有以下几种：磁介质（硬盘，磁带），半导体（内存，固态硬盘，闪存卡等），光介质（光盘）等。不同的存储方式在各方面具有不同的特点，如易失性（断电是否失去数据），容量大小，读写支持（读写，只读，快读慢写，一次性写入等），数据存取方式（连续存取，随机存取），性能（如延迟，吞吐量等），能耗等。下文所说的存储指二级存储，又称外存，或辅存。与此对应的主要存储是指内存，即"运行内存"。事实上只有这一种内存，把移动设备的持久化存储称为内存在技术上是错误的，这些其实是外存。外存与内存的区别在于是否能直接与 CPU 连接。常见的外存设备包括硬盘，固态硬盘等。硬盘 (HDD, Hard Disk Drive)硬盘是一种电子机械设备，使用转动的磁盘和可平面移动的磁头来存取数据。硬盘的存取延迟一般在几毫秒左右。它支持随机存取，每秒大概几十次到二百次。硬盘适用于连续存取较多的场景如多媒体数据或备份等，其吞吐量可达到 100 ~ 200 MB/s.硬盘驱动器中可以有多张磁碟，互相平行重叠，碟间和两侧有读写磁头(Head)。每张碟被划分为若干个同心圆，称为磁道(Track)，每个磁道划分为多个扇区(Sector)；所有碟相同位置的磁道构成一个柱面(Cylinder)。硬盘可以通过 CHS 方式对每个扇区进行寻址：Cylinde 编号(0 ~ 1023)，Head 编号(0~254)，Sector(1 ~ 63)。这种方式在常见的 512 字节扇区大小下，能处理的最大硬盘容量是 7844 GB。历史上这些值直接对应硬盘的内部的物理器件，但随着存储密度的增大，硬盘向 BIOS 报告的参数也变为了逻辑数据。为解决更大容量的寻址问题，同时提升部分场景的性能，AF (Advanced Formatting) 技术将扇区大小调整为 4 KB。较新的存储系统现在主要采用 LBA(Logical Block Addressing) 寻址方式，直接使用 32 位或 64 位的扇区编号。硬盘根据磁极与盘面的方向关系可分为 LMR 和 PMR 两种。LMR(Longitudinal Magnetic Recording, 纵向磁性记录)仅用于早期的硬盘，磁极与盘面平行。PMR(Perpendicular Magnetic Recording, 垂直磁性记录)是目前所有硬盘都采用的技术，磁极与盘面垂直，这样能做到更高的数据密度。PMR 又分为两种：CMR 和 SMR。CMR(Conventional PMR) 中磁道之间留有空白区域，以避免存取时与相邻磁道相互影响。SMR(Shingled Magnetic Recording , 叠瓦磁性记录) 中磁道间没有间隔，修改数据时需要特殊处理，以免影响相邻磁道。SMR 提升了数据存储密度，在性能和稳定性上做了一定的妥协。硬盘的"硬"字是相对于软盘而言的。软盘（Floppy disk）是一种可移动的磁存储媒体，塑料硬壳里边的盘片使用较软的聚酯薄膜制成。硬盘的盘片则由铝或玻璃制成。固态硬盘 (SDD, Solid-state Drive/Solid-state Disk)固态硬盘使用闪存芯片存储数据。固态硬盘的存取延迟一般在几十到几百微秒之间。随机存取每秒可以达到千次以上，并且可在内部使用类似 RAID 0 的技术进一步提升性能。吞吐量一般大于硬盘，高端的产品甚至经常被物理接口(SATA, PCIE等)所限制。由于 NAND(Not AND) 闪存的特性，固态硬盘长期不通电会损失数据（正常室温情况下若干年）。闪存芯片可按字节读取，但是写入时则只能在特定情况下进行：代表 1 的位(bit)可被改写为 0, 反之则不行；只有整块(一般单块在 16KB 到 512KB 之间)擦写才能将 0 变为 1。闪存具有有限的 P/E 周期(Program-Eraspe)，数据写入量过大会造成写入耗尽(wear out)。由于这些特性，针对固态硬盘，固件及软件系统需要进行相关的处理，才能将保持高性能和保证设备状态。文件系统可以发送 TRIM 命令，通知 SSD 块已经不再使用，可以擦除；固件可能会将数据分布到不同的位置，以平衡不同块的写入量。固态硬盘里边没有"盘"。它不包含可运动的机械装置，因此称为"固态"。它也不包含磁性组件，但是由于习惯和翻译的原因，通常还是把它和硬盘等可按块随机访问的二级存储设备统称为磁盘(disk)。S.M.A.R.T (Self-Monitoring, Analysis and Reporting Technology)磁盘可能因为机械磨损，材料降级等原因发生故障。为增强数据安全性，现代的磁盘基本都支持通过 S.M.A.R.T. 向软件系统报告自身健康状…

字符集与编码
type: item
date: 2020-09-13T11:20:00+08:00
description: 字符集和编码字符集(Character Set)是字符的集合，定义系统能处理哪些字符；编码(Encoding)则规定这些字符在计算机内部的表示方式。这里字符是抽象的概念，编码将其与二进制数据进行映射。由于编码通常依赖于字符集，实践中两者经常是绑定或互指的。常见的汉字编码方案GB2312，其全名为《信息交换用汉字编码字符集·基本集》；而 HTML 中的 标签也混用了字符集（charset）和编码的概念。既然是集合，字符集就会有超集和子集。如 1995 年发布的GBK(《汉字内码扩展规范》)，就是 GB2312 （发布于 1980 年）的超集；而2000 年发布的GB18030（《信息技术 中文编码字符集》）又是 GBK的超集。代码页代码页就是字符集加上编码。Windows提供了很多代码页选项，用于支持不同的语言文字。每个代码页有一个编号，简体中文对应的编号为936，其对应的字符集为GBK。你可以在命令行中执行命令reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage /f ACP，查看系统当前设置的代码页编号：C:\>reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage /f ACP HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage ACP REG_SZ 936 搜索结束: 找到 1 匹配。 C:> 代码页是 Windows 系统的术语。在 Linux 系统中，类似的概念是locale，不过当前Linux 一般默认编码方式都是 utf-8，对应的字符集是 Unicode。ANSI 编码ANSI 编码代表 Windows 系统中当前代码页对应的编码，亦即系统默认编码。这个术语经常在 Windows平台使用，但实际上是被误用的。理论上，它应该等同于ANSI 在 1986 年发布的US-ASCII。现实中，它可以代表任意编码，甚至可以与ASCII 完全不兼容，只要设置为系统默认编码。UnicodeUnicode是一套标准，包含多语言统一的字符集及其相关编码，以及在这个字符集上进行文本处理的相关规则。Unicode 当前版本(12.1)共规定了 137,929个字符。它们不仅囊括了当前全球使用的主要语言文字（如拉丁字母，阿拉伯文字，简繁汉字等），还包含了很多符号（货币符号，标点符号，数学符号，几何图形，emoji等），甚至还有仅在史料上使用的文字（如楔形文字，埃及象形文字等）。在 Unicode中，每个字符被分配了一个数值(Code Point，代码点)和一个名称。比如字母A的名称是LATIN CAPITAL LETTER A(大写拉丁字母A)。它对应的数值是65，通常写作 U+0041(41是十六进制数，等于10进制的65)。除此之外，Unicode还定义了各个字符的一系列属性，比如是否是大写字母，是否代表数字，书写方向（左到右还是右到左），宽度（半角还是全角）等。基于这些属性，Unicode提供了大小写转换，文本换行，双向书写显示等相关算法。Unicode 字符集被分为十七个子集(Plane，平面或位面)，每个子集最多可包含65536 个字符，因此总共可以有 1,114,112 个字符。其中第一个子集(Plane0)包含最常用的字符，被称为 BMP(Basic Multilingual Plane,基本多文种平面)。 BMP 中为 UTF-16 中的代理对(Surrogate Pair)保留了2048 个位置，只剩下 63488 个有效字符空间（因此 Unicode中实际最多有1,112,064个字符）。BMP中的字符可以用四位十六进制数(U+xxxx)表示，其它的字符需要五位或更多。UTF-8, UTF-16, UTF-32这些是 Unicode 标准中规定的几种编码方式。UTF 是 Unicode Transformation Format 的缩写。UTF-8 是一种变长编码，以字节为基本单位，单个字符占用的字节数可能是 1（U+0000 ~ U+007F，128个位置，所有的 ASCII 字符），2（U+0080 ~ U+07FF, 1920个位置，主要是各种字母和符号），3（U+0800 ~ U+FFFF，63488个位置，BMP中所有其它字符，包括绝大部分常用汉字）或4（U+10000 ~ U+10FFFF，1048576个位置，所有其他字符）。 UTF-8 的主要优势在于兼容 ASCII，面向字节因而无需考虑字节顺序。现在 UTF-8 是互联网上使用率最高…

Smobiler分析对比
type: item
date: 2017-09-13T08:26:00+08:00
description: 维度phonegap代表Smobiler备注跨平台性通用android/ios劣势不明显人员技术依赖js + html5 + css + (java + oc/swift等等)C#/VB + ( ? )技术平台不同，不太好作对比，不过js dever覆盖面更广, 因此以phonegap为代表的技术更易推广，括号里面是定制化开发使用到的技术集成开发工具不一致Visual Studio完爆发布直接编译成目标平台的安装文件依赖client + Server考虑到使用体验和推广问题，劣势很明显

高并发场景下System.currentTimeMillis()的性能优化
type: item
date: 2017-08-17T08:33:00+08:00
description: System.currentTimeMillis()的调用比new一个普通对象要耗时的多（具体耗时高出多少我还没测试过，有人说是100倍左右）System.currentTimeMillis()之所以慢是因为去跟系统打了一次交道后台定时更新时钟，JVM退出时，线程自动回收，得到的数据10亿：43410,206,210.72815533980582%1亿：4699,29,162.0344827586207%1000万：480,12,40.0%100万：50,10,5.0%参考代码如下：import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; public class SystemClock { private final long period; private volatile long now; private static final SystemClock instance = new SystemClock(1); private SystemClock(long period) { this.period = period; // this.now = new AtomicLong(System.currentTimeMillis()); this.now = System.currentTimeMillis(); scheduleClockUpdating(); } public static long now() { return instance.currentTimeMillis(); } public static Date nowDate() { return new Date(instance.currentTimeMillis()); } private void scheduleClockUpdating() { ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { public Thread newThread(Runnable runnable) { Thread thread = new Thread(runnable, "SystemClock"); thread.setDaemon(true); return thread; } }); scheduler.scheduleAtFixedRate(new Runnable() { public void run() { now = System.currentTimeMillis(); } }, period, period, TimeUnit.MILLISECONDS); } private long currentTimeMillis() { return now; } }

验证和授权
type: item
date: 2017-04-01T13:23:00+08:00
description: 关于验证和授权，很多计算机程序员都分不清楚，举个例子。美女许天仙在上网聊天。慕名已久的王二狗邀她见面，为了表示诚意，二狗开通了视频。天仙看到二狗的真面目后说：“我只和帅哥见面。”张三风听闻此事，也去约天仙见面，他发了一张照片过去。天仙还是拒绝了。三风不解：“你不是喜欢帅哥吗？”天仙答曰：“你竟然想用我的男神竹野内丰（读者如认为他不是帅哥可自行换成金秀贤，笔者十分好奇“美男”、“帅哥”之类的概念外延有多大，长相差异如此大的两人怎么能被划定为一类人）的照片骗我？”上面的场景用计算机技术的术语来解读就是：王二狗验证成功，授权失败。张三风授权没问题，如果验证不失败。在对用户名和密码的讨论里，我们已经谈到身份验证。不过一个用户通过验证并不表示他就可以进行系统里所有的操作，对很多有限制的操作，验证还仅仅是整个安全审核过程的第一步。我们在使用软件和浏览网站时，经常会遇到一个词——权限。游戏里很多装备要付费之后才能使用，论坛里不同级别的用户有不等的阅读和发帖权限，公司里的软件系统各个账户具备不同的功能，甚至你电脑上运行的不同软件本身也有不同的权限。“您没有权限进行以下操作”是一个令人懊恼的提示。何谓权限？一个系统里注册了很多账号，有很多操作、功能和资源，有一部分功能只有一部分账号能使用，一部分资源只有一部分账户能访问，这种账号和功能、资源间关系的差异就是权限的来源，换句话说，只要不是所有账户都能无差别地执行系统的所有操作，就存在权限的概念。而系统对账户的权限进行分配和验证的过程就称为授权。授权（authorization）和验证（authentication）在计算机技术里含义相差很远，英文拼写却有些相似，在实际的软件系统中，这两个过程也总是相继发生，合作构成系统的安全机制。验证首先确认某个用户是否具有他所声称的身份（identity），也就是排除冒名顶替。用户通过验证后，系统就明确了他是谁。但是哪些事情他能做，哪些不能做就是授权所解决的问题。

设计简单的后台管理的数据排序
type: item
date: 2017-01-06T10:27:00+08:00
description: 场景:前端需要展示一个列表（如：首页的轮播图），后台需要能够控制列表数据的排序。需求：自动规则 + 运营干预，干预包括：降低排名，提升排名，设定位置和新增item实现：在Web后台管理系统中，列表形式的数据排序功能是很常见的需求。要实现这类功能，给数据表增加一个排序字段order，越大排名越靠前，数字相同时按照自动规则（如：id）排序，这样，就可以实现了：idnameorder1tom22jack33bob1实际的排序显示为：jack tom bob 既然是后台，那么主要的用户是公司的运营人员，本着提高使用效率的原则，在草稿纸上画了个原型让运营对比，然后来得出哪个更符合他的使用习惯，再做确定，结果沟通下来运营理想中操作是想要在后台直接拖动排序。现在问题来了，应该怎么设计这个运营干预的功能：方案1：填写数字方案2：上移、下移方案3：手动控制加分or减分（+1/-1 +10/-10）方案4：如运运营所想，提供拖动排序功能方案1的技术实现最简单，对开发来说最方便，但对运营来说却比较麻烦。方案2的技术实现其实较复杂，比如上移一位，需要先查询当前项的前一项的order, 然后让当前项的order+1并保存, 对运营来说操作较简单。方案3的技术实现比较简单，比如点击-10，只需更新当前项的order-10并保存，但有可能在order-10后当前项的顺序还没有变（如：前一项：12，当前项11，后一项：0），对运营来说操作比较简单。方案4的技术实现比较复杂，需要使用js实现拖拽数据项的效果等，在拖动结束或点击保存后判断当前的所有数据顺序并保存，对运营来说操作简单。综合比较技术实现复杂度：方案1<方案3<方案2<方案4操作便捷性：方案4<方案3<方案2<方案1分析一下大多数的场景，看到列表的数据是有限的，一般都是5条、10条、20条左右，由于我所在的是创业公司，开发资源有限，选择方案3在当前情况下是合适的实现方式。经过了一番沟通，在许诺了下午茶后，说服了产品、运营接收这中方案。图中就是我用方案3实现的一个界面，单个箭头的是+1 -1，俩个箭头的分别是+10 -10，分别用于微调和较大位置距离的调整，在管理大多数少量数据列表的场景下对于运营人员是够用了。

JSP与MySQL交互的中文乱码解决方案及总结
type: item
date: 2016-12-15T22:51:00+08:00
description: 首先实现了一个StringConvert bean（GBtoISO()和ISOtoGB()两个方法），解决了与MySQL数据库交互的时候的部分中文乱码问题：在JSP程序中读取MySQL的中文内容，用这两个方法可以解决乱码问题。 但是从JSP写入到MySQL的中文内容都成了乱码，并且再读出来的时候也显示为“？？”，在这里应该出现了编码转换过程中的字符信息丢失。郁闷的是，我在命令行窗口中登陆到MySQL后，执行如INSERT INTO customer VALUES(''字符'',...)这样的语句时，写入到数据表中的中文内容又是显示正常的！！！数据库使用的字符集是utf8。 碰壁多次，终于发现一条解决问题的路径：查看MySQL手册的时候，看到一条这样的语句：To allow multiple character sets to be sent from the client, the "UTF-8" encoding should be used, either by configuring "utf8" as the default server character set, or by configuring the JDBC driver to use "UTF-8" through the characterEncoding property. 此外，在查阅《MySQL权威指南》时，发现在查询语句中可以使用这样的语法将字符串转换到一个给定的字符集：_charset str。 其中charset必须是服务器支持的某个字符集。在本例中，shopdb数据库使用的默认字符集是utf8，于是开始测试： 先输入INSERT INTO publish Values(''8'',_gb2312 ''高等教育出版社'') 写入后中文变成“？？” 再试INSERT INTO publish Values(''8'',_gbk ''高等教育出版社'') 结果同上 INSERT INTO publish Values(''8'',_utf8 ''高等教育出版社'') 这下更干脆，什么都没有！！ 快疯了!!没办法，用show character set;命令查看MySQL支持的字符集，心想我都试一遍总有一个能成功吧。浏览了一下，发现没有几个熟悉的字符集，就只剩下一个latin1(ISO-8859-1)比较常见了，不会是它吧，一试之下果然便是。 INSERT INTO publish Values(''8'',_latin1 ''高等教育出版社'') 输入中文能够正确显示。 这下总算找到方法了，把Tomcat下配置的数据库连接池的url改为＂...characterEncoding=UTF-8＂，然后把写入数据库的中文内容用 String s2 = new String(s1.getBytes("gb2312"),"ISO-8859-1")进行转码，其中s1为中文字符串．然后再写入到数据库一切显示正常。 为解决这个问题查看了n多资料，现作一个总结：由于字符集和字符编码方式的不同，在OS以及程序之间传递数据（尤其是multiple character sets中的数据）时便会产生乱码以及字符信息的丢失．解决这个问题的关键便是了解数据输出端和接收端使用的字符集和字符编码方式，如果这两种编码方式不同，便需要在数据出口或入口处进行 转码。一般的说，在编写代码,编译，以及运行期间都会字符数据的传递，因此需要特别小心。 在编写代码的时候，你可能会使用某种开发工具，例如我正在使用的Eclipse．或许在写的时候一切正常，可是一旦保存后再次打开文档，所有的中文字符都变成了乱码。这是因为在编写的时候，这些字符数据都在内存的某个stream中，ok，这没问题，可是保存的时候这个stream中的数据会被写入到硬盘，使用的就是你的开发工具默认的编码方式，如果很不幸你的开发工具默认编码方式是ISO-8859-1，中文字符信息就不能正确地存储。Eclipse中可以这样查看并修改默认字符编码方式：Project->Properties->info，这里有＂default encoding for text file＂。如果设置为GBK，那么编写代码并保存这关就过了。 对于JSP程序而言，编写完代码后就交给Container，首先它们会被转成.java文件，然后编译成.class才能提交给服务器执行．这个过程也存在字符编码问题．java编译器(javac)使用操作系统的语言环境作为默认的字符编码方式，JRE(Java Runtime Environment)也是这样。只有当编译和运行环境的字符编码方式与存储源文件的编码方式相同时，中文字符才能正确地显示。否则就需要在运行时进行转码…

catalana.bat详解
type: item
date: 2016-12-14T22:38:00+08:00
description: Catalina.bat是tomcat所有脚本中最重要的脚本，完成几乎所有的tomcat操作。如启动，关闭等等,都是由catalina.bat脚本来完成的。接下来，我将对Tomcat catalina.bat脚本进行分析。 首先省去catalina.bat开头诸多注解，这些注解主要是讲解各个变量是干什么的。需要的话，自己看下英文就可以了。这里就不翻译了。 rem Guess CATALINA_HOME if not defined 查看是否在tomcat目录下，与startup.bat里相同，不解释了。 set CURRENT_DIR=%cd% if not "%CATALINA_HOME%" == "" goto gotHome set CATALINA_HOME=%CURRENT_DIR% if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome cd .. set CATALINA_HOME=%cd% cd %CURRENT_DIR% :gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome rem Get standard environment variables if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat" 如果存在setenv.bat脚本，调用它，我的tomcat 没有这个脚本 rem Get standard Java environment variables if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath 查看是否存在setclasspath.bat脚本，如果存在，转到okSetclasspath位置 echo Cannot find %CATALINA_HOME%\bin\setclasspath.bat 否则输出下面两行，并退出 echo This file is needed to run this program goto end :okSetclasspath okSetclasspath位置 set BASEDIR=%CATALINA_HOME% 设定BASEDIR变量与CATALINA_HOME变量值相同 call "%CATALINA_HOME%\bin\setclasspath.bat" %1 调用setclasspath.bat脚本并加上参数 if errorlevel 1 goto end 如果存在错误 退出 rem Add on extra jar files to CLASSPATH 设定JSSE_HOME变量，如果存在加入CLASSPATH，不存在跳过 if "%JSSE_HOME%" == "" goto noJsse 检查是否存在JSSE_HOME变量 set CLASSPATH=%CLASSPATH%;%JSSE_HOME%\lib\jcert.jar;%JSSE_HOME%\lib\jnet.jar;%JSSE_HOME%\lib\jsse.jar 如果有加入到CLASSPATH变量后面 :noJsse set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar 将bootstrap.jar加入到CLASSPATH里 if not "%CATALINA_BASE%" == "" goto gotBase 如果CATALINA_BASE变量不为空，跳过，转到gotBase位置 set CATALINA_BASE=%CATALINA_HOME% 如果为空，将CATALINA_BASE设为CATALINA_HOME变量的值 :gotBase if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir CATALINA_TMPDIR不为空，跳过，转到gotTmpdir位置 set CATALINA_TMPDIR=%CATALINA_BASE%\temp 如果为空，将 CATALINA_TMPDIR设为%CATALINA_BASE%\temp变量的值（即tomcat\temp）…

tomcat的JVM设置和连接数设置
type: item
date: 2016-09-26T14:44:00+08:00
description: 一、Tomcat的JVM提示内存溢出查看%TOMCAT_HOME%\logs文件夹下，日志文件是否有内存溢出错误二、修改Tomcat的JVM1、错误提示：java.lang.OutOfMemoryError: Java heap spaceTomcat默认可以使用的内存为128MB，在较大型的应用项目中，这点内存是不够的，有可能导致系统无法运行。常见的问题是报Tomcat内存溢出错误，Out of Memory(系统内存不足)的异常，从而导致客户端显示500错误，一般调整Tomcat的使用内存即可解决此问题。 Windows环境下修改“%TOMCAT_HOME%\bin\catalina.bat”文件，在文件开头增加如下设置：set JAVA_OPTS=-Xms256m -Xmx512m Linux环境下修改“%TOMCAT_HOME%\bin\catalina.sh”文件，在文件开头增加如下设置：JAVA_OPTS=’-Xms256m -Xmx512m’ 其中，-Xms设置初始化内存大小，-Xmx设置可以使用的最大内存。2、错误提示：java.lang.OutOfMemoryError: PermGen space原因：PermGen space的全称是Permanent Generation space,是指内存的永久保存区域，这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中，它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理，所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误，这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。解决方法：在catalina.bat的第一行增加：set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m在catalina.sh的第一行增加：JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m三、JVM设置堆的尺寸 -Xmssize in bytes设定Java堆的初始尺寸，缺省尺寸是2097152 (2MB)。这个值必须是1024个字节（1KB）的倍数，且比它大。（-server选项把缺省尺寸增加到32M。） -Xmnsize in bytes为Eden对象设定初始Java堆的大小，缺省值为640K。（-server选项把缺省尺寸增加到2M。) -Xmxsize in bytes设定Java堆的最大尺寸，缺省值为64M，（-server选项把缺省尺寸增加到128M。） 最大的堆尺寸达到将近2GB（2048MB）。 请注意：很多垃圾收集器的选项依赖于堆大小的设定。请在微调垃圾收集器使用内存空间的方式之前，确认是否已经正确设定了堆的尺寸。 垃圾收集:内存的使用 -XX:MinHeapFreeRatio=percentage as a whole number修改垃圾回收之后堆中可用内存的最小百分比，缺省值是40。如果垃圾回收后至少还有40%的堆内存没有被释放，则系统将增加堆的尺寸。 -XX:MaxHeapFreeRatio=percentage as a whole number改变垃圾回收之后和堆内存缩小之前可用堆内存的最大百分比，缺省值为70。这意味着如果在垃圾回收之后还有大于70%的堆内存，则系统就会减少堆的尺寸。 -XX:NewSize=size in bytes为已分配内存的对象中的Eden代设置缺省的内存尺寸。它的缺省值是640K。（-server选项把缺省尺寸增加到2M。） -XX:MaxNewSize=size in bytes允许您改变初期对象空间的上限，新建对象所需的内存就是从这个空间中分配来的，这个选项的缺省值是640K。（-server选项把缺省尺寸增加到2M。） -XX:NewRatio=value改变新旧空间的尺寸比例，这个比例的缺省值是8，意思是新空间的尺寸是旧空间的1/8。 -XX:SurvivorRatio=number改变Eden对象空间和残存空间的尺寸比例，这个比例的缺省值是10，意思是Eden对象空间的尺寸比残存空间大survivorRatio+2倍。 -XX:TargetSurvivorRa…

详解Tomcat配置JVM参数步骤
type: item
date: 2016-09-25T14:43:00+08:00
description: Tomcat默认可以使用的内存为128MB，在较大型的应用项目中，这点内存是不够的，需要调大,并且Tomcat本身不能直接在计算机上运行，需要依赖于硬件基础之上的操作系统和一个java虚拟机。这里向大家描述一下如何使用Tomcat配置JVM参数，Tomcat本身不能直接在计算机上运行，需要依赖于硬件基础之上的操作系统和一个java虚拟机。您可以选择自己的需要选择不同的操作系统和对应的JDK的版本，但还是推荐您使用Sun公司发布的JDK。Tomcat配置JVM参数Tomcat本身不能直接在计算机上运行，需要依赖于硬件基础之上的操作系统和一个java虚拟机。您可以选择自己的需要选择不同的操作系统和对应的JDK的版本（只要是符合Sun发布的Java规范的），但我们推荐您使用Sun公司发布的JDK。确保您所使用的版本是最新的，因为Sun公司和其它一些公司一直在为提高性能而对java虚拟机做一些升级改进。一些报告显示JDK1.4在性能上比JDK1.3提高了将近10%到20%。可以给Java虚拟机设置使用的内存，但是如果你的选择不对的话，虚拟机不会补偿。可通过命令行的方式改变虚拟机使用内存的大小。如下表所示有两个参数用来设置虚拟机使用内存的大小。参数 描述-Xms JVM初始化堆的大小-Xmx JVM堆的最大值这两个值的大小一般根据需要进行设置。初始化堆的大小执行了虚拟机在启动时向系统申请的内存的大小。一般而言，这个参数不重要。但是有的应用程序在大负载的情况下会急剧地占用更多的内存，此时这个参数就是显得非常重要，如果虚拟机启动时设置使用的内存比较小而在这种情况下有许多对象进行初始化，虚拟机就必须重复地增加内存来满足使用。由于这种原因，我们一般把-Xms和-Xmx设为一样大，而堆的最大值受限于系统使用的物理内存。一般使用数据量较大的应用程序会使用持久对象，内存使用有可能迅速地增长。当应用程序需要的内存超出堆的最大值时虚拟机就会提示内存溢出，并且导致应用服务崩溃。因此一般建议堆的最大值设置为可用内存的最大值的80%。Tomcat默认可以使用的内存为128MB，在较大型的应用项目中，这点内存是不够的，需要调大。Windows下，在文件/bin/catalina.bat，Unix下，在文件/bin/catalina.sh的前面，增加如下设置：JAVA_OPTS='-Xms【初始化内存大小】 -Xmx【可以使用的最大内存】'需要把这个两个参数值调大。例如：JAVA_OPTS='-Xms256m -Xmx512m'，表示初始化内存为256MB，可以使用的最大内存为512MB。另外需要考虑的是Java提供的垃圾回收机制。虚拟机的堆大小决定了虚拟机花费在收集垃圾上的时间和频度。收集垃圾可以接受的速度与应用有关，应该通过分析实际的垃圾收集的时间和频率来调整。如果堆的大小很大，那么完全垃圾收集就会很慢，但是频度会降低。如果你把堆的大小和内存的需要一致，完全收集就很快，但是会更加频繁。调整堆大小的的目的是最小化垃圾收集的时间，以在特定的时间内最大化处理客户的请求。在基准测试的时候，为保证最好的性能，要把堆的大小设大，保证垃圾收集不在整个基准测试的过程中出现。如果系统花费很多的时间收集垃圾，请减小堆大小。一次完全的垃圾收集应该不超过3-5秒。如果垃圾收集成为瓶颈，那么需要指定代的大小，检查垃圾收集的详细输出，研究垃圾收集参数对性能的影响。一般说来，你应该使用物理内存的80%作为堆大小。当增加处理器时，记得增加内存，因为分配可以并行进行，而垃圾收集不是并行的。