Graphics2D 验证码生成高性能关键在于资源复用与精细控制:复用 BufferedImage 尺寸/类型、静态 Font、ThreadLocal Random;禁用冗余渲染提示;适度干扰;批量计算坐标;及时 dispose;避免运行时创建对象。

Graphics2D 在内存中绘制验证码,本质是用 BufferedImage 搭配 Graphics2D 画笔完成纯内存图像合成,不涉及磁盘 I/O 或外部依赖,因此性能高、响应快,适合高并发 Web 场景。
关键性能优化点
真正影响性能的不是“画了什么”,而是“怎么画”和“资源怎么管”:
-
复用 BufferedImage 尺寸与类型:固定宽高(如 130×40),优先用
BufferedImage.TYPE_INT_ARGB或TYPE_INT_RGB;避免每次 new 不同尺寸或类型,减少 GC 压力 -
禁用冗余渲染提示:只开启必要优化项,例如:
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
但关闭耗时项如KEY_FRACTIONALMETRICS或KEY_TEXT_ANTIALIASING(除非字体特别小) -
干扰元素适度控制:100 条干扰线比 300 条快近 2 倍;建议线数 ≤ 80、噪点 ≤ 200,用
drawLine()而非fillOval()(后者更重) -
字符绘制批量计算坐标:提前算好每个字符的 x/y 偏移,避免在循环里反复调用
getStringBounds()——该方法内部触发字体度量计算,开销显著
避免常见内存/性能陷阱
看似简单的绘图,容易因细节引入隐性瓶颈:
-
别在每次请求中 new Font 实例:Font 构造较重,应作为静态常量复用,例如:
private static final Font CODE_FONT = new Font("Arial", Font.BOLD, 24); - setColor() 和 setFont() 频繁切换会拖慢速度:把同色/同字体的绘制合并,比如所有干扰线用一种灰度色一次性画完,再统一换色画字符
- 务必调用 g2d.dispose():Graphics2D 是 AWT 资源封装,不释放会导致句柄泄漏,尤其在 Tomcat 等容器中长期运行易 OOM
-
慎用随机字体家族名:
GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()是同步方法且结果不可缓存,首次调用可能卡几十毫秒
轻量级高性能示例结构
一个生产可用的验证码生成器,核心逻辑应极简清晰:
- 构造时预生成字符集(如剔除 0/O/1/l 的 32 位安全码表),避免运行时字符串拼接
- 用 ThreadLocal 缓存
Random实例,避免多线程竞争java.util.Random内部 CAS - 字符颜色从预设数组中轮询(如 {Color.BLUE, Color.GRAY, Color.DARK_GRAY}),比每次 new Color 更快
- 输出前设置响应头:
response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate,max-age=0");,防止浏览器或 CDN 缓存旧图
不复杂但容易忽略。核心就三点:复用资源、减少对象创建、及时释放句柄。










