如何处理java2d中的ClassCastException (Bug-ID 7172749)

时间:2022-05-27 12:01:46

I have the bad luck of suffering from a bug in java8, that doesn't seem to be a big issue for anybody else, so Oracle is not going to fix it before java9.
The bug has Bug-ID 7172749 (also note the related and duplicate bugs) and it just happens all the time on a certain linux machine.
I'm experiencing the problem on an Ubuntu 14.04.3 LTS with jdk1.8.0_u66.
However, on another box with Ubuntu 12.04.3 LTS and the same JDK version, i can't reproduce the problem at all.

我很不幸在java8中遇到了一个bug,这对其他人来说似乎不是什么大问题,所以Oracle不会在java9之前修复它。这个bug有bug - id 7172749(也要注意相关的和重复的bug),并且在特定的linux机器上经常发生。我在Ubuntu 14.04.3 LTS上遇到了这个问题。然而,在另一个带有Ubuntu 12.04.3 LTS和相同JDK版本的盒子上,我根本无法重现这个问题。

What puzzles me is that this doesn't seem to be a showstopper for anybody else, so I guess maybe I'm making a particularly dump mistake.. I'm running the Oracle-JDK (as opposed to OpenJDK), because our customer uses the same version (albeit on windows) and the idea was to be close to their environment.

令我困惑的是,这似乎对其他人来说都不是什么好东西,所以我想我可能犯了一个很严重的错误。我正在运行Oracle-JDK(相对于OpenJDK),因为我们的客户使用了相同的版本(尽管是在windows上),而这个想法是接近于他们的环境。

So, my question is, how to get around this problem (e.g. install X11-library xy, start my java-program with a magic -XXjava2dfailsafe parameter or sth along these lines)
and join the flock of people who can comfortably wait for the actual problem to be fixed by oracle?

因此,我的问题是,如何绕过这个问题(例如,安装X11-library xy,用一个神奇的-XXjava2dfailsafe参数或其他参数启动我的java程序),加入那些能够轻松等待oracle解决实际问题的人的行列?

Best regards Tobi

托比问好

Btw, my stackstrace looks like this:

顺便说一句,我的stackstrace看起来是这样的:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData
    at sun.java2d.xr.XRPMBlitLoops.cacheToTmpSurface(XRPMBlitLoops.java:145)
    at sun.java2d.xr.XrSwToPMBlit.Blit(XRPMBlitLoops.java:353)
    at sun.java2d.SurfaceDataProxy.updateSurfaceData(SurfaceDataProxy.java:498)
    at sun.java2d.SurfaceDataProxy.replaceData(SurfaceDataProxy.java:455)
    at sun.java2d.SurfaceData.getSourceSurfaceData(SurfaceData.java:233)
    at sun.java2d.pipe.DrawImage.renderImageCopy(DrawImage.java:566)
    at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:67)
    at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1014)
    at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3318)
    at sun.awt.image.ImageRepresentation.drawToBufImage(ImageRepresentation.java:813)
    at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1021)
[...]

1 个解决方案

#1


14  

I figured out a workaround for the problem.

我想出了解决这个问题的办法。

In short: Start the JVM with the parameter -Dsun.java2d.xrender=false.

简而言之:使用参数-Dsun.java2d.xrender=false启动JVM。

With that option, I didn't see the problem anymore.

有了这个选项,我再也看不到问题了。

Background Info

The Bug JDK-7172749 has now recently been fixed with jdk9 build 124 and the bugfix has been backported via JDK-8158068 to jdk8 update 112. You can download the jdk8u112 build preview from here: JDK8 Early Access Releases.

现在,JDK-7172749已经与jdk9构建了,而bugfix已经通过JDK-8158068返回到jdk8更新112。您可以从这里下载jdk8u112构建预览版:JDK8早期访问发行版。

However, running this build didn't fix the problem for me.

然而,运行这个构建并不能解决我的问题。

My situation, where I experience the bug: I'm running jEdit and I see these ClassCastException after I resume my Linux from suspend-to-RAM. It's the same stacktrace:

我的情况是,我在这里遇到了问题:我运行jEdit,在我从挂起到ram重新启动Linux之后,我看到了这些ClassCastException。异常堆栈是一样的:

10:04:10 [AWT-EventQueue-0] [error] AWT-EventQueue-0: java.lang.ClassCastException: sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData
10:04:10 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at sun.java2d.xr.XRPMBlitLoops.cacheToTmpSurface(XRPMBlitLoops.java:145)

The effect of this exception is, that the whole window of jEdit or parts are not drawn and stay white.

这个例外的影响是,jEdit或部分的整个窗口没有被绘制,并且保持白色。

Looking at the patch for the backported bugfix, it actually fixed a ClassCastException in a different class, namely in sun.java2d.xr.XRRenderer.

查看后端bug修复的补丁,它实际上在另一个类(即sun.java2d.xr.XRRenderer)中修复了ClassCastException。

So, it's not suprising that this didn't fix my problem.

这并没有解决我的问题。

Another google search revealed bug JDK-6975408 which made me aware of the system property sun.java2d.xrender.

另一个谷歌搜索显示了bug JDK-6975408,这让我意识到了system属性sun.java2d.xrender。

More searching:

更多的搜索:

  • This option is described in System Properties for Java 2D Technology

    这个选项在Java 2D技术的系统属性中进行了描述

    Quote:

    引用:

    xrender

    xrender

    Intended use: To enable the XRender-based Java 2D rendering pipeline for modern X11-based desktops, offering improved graphics performance.

    预期用途:为现代基于x11的桌面启用基于xrender的Java 2D呈现管道,提供改进的图形性能。

    Introduced: Java SE 7

    介绍:Java SE 7

    Default value: false

    默认值:假

    How to use: The pipeline is disabled by default, but may be enabled by setting the command line property -Dsun.java2d.xrender=true. Older X11 configurations may not be able to support XRender. The verbose form, -Dsun.java2d.xrender=True, can be used to enable a message to stdout indicating whether the pipeline was actually enabled.

    如何使用:管道在默认情况下是禁用的,但是可以通过设置命令行属性-Dsun.java2d.xrender=true来启用。旧的X11配置可能不能支持XRender。详细的形式,-Dsun.java2d。xrender=True,可用于将消息发送给stdout,以指示是否启用了管道。

  • Yes, it's a feature, that has been added with Java7: Xrender pipeline now in JDK7 master

    是的,这是一个特性,现在已经在JDK7 master中添加了Java7: Xrender管道

    See also Enhancements in Java SE 7

    参见Java SE 7中的增强

  • And with Java8, it is now enabled by default: Java8: Xrender Java2D pipeline enabled by default

    在Java8中,默认情况下启用了它:Java8: Xrender Java2D管道默认启用。

    According to the comments of this blog, the XRender pipeline is relevant only for Java2D, AWT and Swing - other GUI frameworks (JavaFX, SWT, ...) are not affected:

    根据本博客的评论,XRender管道仅适用于Java2D、AWT和Swing——其他GUI框架(JavaFX、SWT、…)不受影响:

    Swing/AWT based application should benefit, SWT/JavaFX/lwjgl/jogl use other codepaths not related to Java2D.

    基于Swing/AWT的应用程序应该受益,SWT/JavaFX/lwjgl/jogl使用与Java2D无关的其他代码页。

    I didn't find something in the release notes, but in the source code, it's obvious, that the XRender pipeline is enabled by default: sun/awt/X11GraphicsEnvironment.java The commit that changed this, was done already in 2011, according to the ticket it was always on with the first jdk8 release. I guess, the reason, I didn't experience this bug earlier, is, that I probably used java7 as a runtime pretty long and eclipse is not affected.

    我在发布说明中没有发现什么,但是在源代码中,很明显,XRender管道在默认情况下是启用的:sun/awt/X11GraphicsEnvironment。根据第一个jdk8发行版的门票,改变这一点的提交已经在2011年完成了。我想,我之前没有遇到过这个错误的原因是,我可能很长时间使用java7作为运行时,eclipse不会受到影响。

Having a closer look again on the duplicated bug reports, there is already one, that would match the stacktrace:

再次仔细查看重复的bug报告,已经有一个与stacktrace匹配的bug报告:

It's bug JDK-8133723: sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData - it's really not a duplicate... However, reproducing this bug might be difficult. It appears only after a suspend-to-RAM cycle.

bug jdk - 8133723:sun.awt.image。不能将BufImgSurfaceData转换为sun.java2d.xr。XRSurfaceData——它实际上不是重复的……然而,复制这个bug可能会很困难。它只在挂起到ram的循环之后出现。

Update 1 - The trigger

The bug is triggered by changing the output display with xrandr, e.g.

这个错误是通过使用xrandr修改输出显示来触发的。

xrandr --output eDP1 --auto --output DVI-1-0 --off

will immediately cause the ClassCastException. As I plug off my monitor before suspend, I assumed, it's the suspend-resume causing this, but that's wrong.

将立即引起ClassCastException。当我在挂起之前关掉显示器时,我认为是挂起的简历造成了这种情况,但这是错误的。

Update 2 - New Java Bug Ticket

There is a new java bug ticket now: JDK-8160328

现在有一个新的java bug票据:JDK-8160328

Update 3 - Fixed with jdk-9-ea-b131

The bug ticket JDK-8160328 has been closed as duplicate of JDK-8147542 - and this one has been fixed with the latest EA build for java 9 (build 131 and later).

错误票据JDK-8160328已经作为JDK-8147542的副本被关闭——这个错误已经用java 9的最新EA构建(构建131和更高版本)修复。

I could confirm, that I no longer get the ClassCastException when switching monitors with xrandr.

我可以确认,在使用xrandr切换监视器时,我不再获得ClassCastException。

#1


14  

I figured out a workaround for the problem.

我想出了解决这个问题的办法。

In short: Start the JVM with the parameter -Dsun.java2d.xrender=false.

简而言之:使用参数-Dsun.java2d.xrender=false启动JVM。

With that option, I didn't see the problem anymore.

有了这个选项,我再也看不到问题了。

Background Info

The Bug JDK-7172749 has now recently been fixed with jdk9 build 124 and the bugfix has been backported via JDK-8158068 to jdk8 update 112. You can download the jdk8u112 build preview from here: JDK8 Early Access Releases.

现在,JDK-7172749已经与jdk9构建了,而bugfix已经通过JDK-8158068返回到jdk8更新112。您可以从这里下载jdk8u112构建预览版:JDK8早期访问发行版。

However, running this build didn't fix the problem for me.

然而,运行这个构建并不能解决我的问题。

My situation, where I experience the bug: I'm running jEdit and I see these ClassCastException after I resume my Linux from suspend-to-RAM. It's the same stacktrace:

我的情况是,我在这里遇到了问题:我运行jEdit,在我从挂起到ram重新启动Linux之后,我看到了这些ClassCastException。异常堆栈是一样的:

10:04:10 [AWT-EventQueue-0] [error] AWT-EventQueue-0: java.lang.ClassCastException: sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData
10:04:10 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at sun.java2d.xr.XRPMBlitLoops.cacheToTmpSurface(XRPMBlitLoops.java:145)

The effect of this exception is, that the whole window of jEdit or parts are not drawn and stay white.

这个例外的影响是,jEdit或部分的整个窗口没有被绘制,并且保持白色。

Looking at the patch for the backported bugfix, it actually fixed a ClassCastException in a different class, namely in sun.java2d.xr.XRRenderer.

查看后端bug修复的补丁,它实际上在另一个类(即sun.java2d.xr.XRRenderer)中修复了ClassCastException。

So, it's not suprising that this didn't fix my problem.

这并没有解决我的问题。

Another google search revealed bug JDK-6975408 which made me aware of the system property sun.java2d.xrender.

另一个谷歌搜索显示了bug JDK-6975408,这让我意识到了system属性sun.java2d.xrender。

More searching:

更多的搜索:

  • This option is described in System Properties for Java 2D Technology

    这个选项在Java 2D技术的系统属性中进行了描述

    Quote:

    引用:

    xrender

    xrender

    Intended use: To enable the XRender-based Java 2D rendering pipeline for modern X11-based desktops, offering improved graphics performance.

    预期用途:为现代基于x11的桌面启用基于xrender的Java 2D呈现管道,提供改进的图形性能。

    Introduced: Java SE 7

    介绍:Java SE 7

    Default value: false

    默认值:假

    How to use: The pipeline is disabled by default, but may be enabled by setting the command line property -Dsun.java2d.xrender=true. Older X11 configurations may not be able to support XRender. The verbose form, -Dsun.java2d.xrender=True, can be used to enable a message to stdout indicating whether the pipeline was actually enabled.

    如何使用:管道在默认情况下是禁用的,但是可以通过设置命令行属性-Dsun.java2d.xrender=true来启用。旧的X11配置可能不能支持XRender。详细的形式,-Dsun.java2d。xrender=True,可用于将消息发送给stdout,以指示是否启用了管道。

  • Yes, it's a feature, that has been added with Java7: Xrender pipeline now in JDK7 master

    是的,这是一个特性,现在已经在JDK7 master中添加了Java7: Xrender管道

    See also Enhancements in Java SE 7

    参见Java SE 7中的增强

  • And with Java8, it is now enabled by default: Java8: Xrender Java2D pipeline enabled by default

    在Java8中,默认情况下启用了它:Java8: Xrender Java2D管道默认启用。

    According to the comments of this blog, the XRender pipeline is relevant only for Java2D, AWT and Swing - other GUI frameworks (JavaFX, SWT, ...) are not affected:

    根据本博客的评论,XRender管道仅适用于Java2D、AWT和Swing——其他GUI框架(JavaFX、SWT、…)不受影响:

    Swing/AWT based application should benefit, SWT/JavaFX/lwjgl/jogl use other codepaths not related to Java2D.

    基于Swing/AWT的应用程序应该受益,SWT/JavaFX/lwjgl/jogl使用与Java2D无关的其他代码页。

    I didn't find something in the release notes, but in the source code, it's obvious, that the XRender pipeline is enabled by default: sun/awt/X11GraphicsEnvironment.java The commit that changed this, was done already in 2011, according to the ticket it was always on with the first jdk8 release. I guess, the reason, I didn't experience this bug earlier, is, that I probably used java7 as a runtime pretty long and eclipse is not affected.

    我在发布说明中没有发现什么,但是在源代码中,很明显,XRender管道在默认情况下是启用的:sun/awt/X11GraphicsEnvironment。根据第一个jdk8发行版的门票,改变这一点的提交已经在2011年完成了。我想,我之前没有遇到过这个错误的原因是,我可能很长时间使用java7作为运行时,eclipse不会受到影响。

Having a closer look again on the duplicated bug reports, there is already one, that would match the stacktrace:

再次仔细查看重复的bug报告,已经有一个与stacktrace匹配的bug报告:

It's bug JDK-8133723: sun.awt.image.BufImgSurfaceData cannot be cast to sun.java2d.xr.XRSurfaceData - it's really not a duplicate... However, reproducing this bug might be difficult. It appears only after a suspend-to-RAM cycle.

bug jdk - 8133723:sun.awt.image。不能将BufImgSurfaceData转换为sun.java2d.xr。XRSurfaceData——它实际上不是重复的……然而,复制这个bug可能会很困难。它只在挂起到ram的循环之后出现。

Update 1 - The trigger

The bug is triggered by changing the output display with xrandr, e.g.

这个错误是通过使用xrandr修改输出显示来触发的。

xrandr --output eDP1 --auto --output DVI-1-0 --off

will immediately cause the ClassCastException. As I plug off my monitor before suspend, I assumed, it's the suspend-resume causing this, but that's wrong.

将立即引起ClassCastException。当我在挂起之前关掉显示器时,我认为是挂起的简历造成了这种情况,但这是错误的。

Update 2 - New Java Bug Ticket

There is a new java bug ticket now: JDK-8160328

现在有一个新的java bug票据:JDK-8160328

Update 3 - Fixed with jdk-9-ea-b131

The bug ticket JDK-8160328 has been closed as duplicate of JDK-8147542 - and this one has been fixed with the latest EA build for java 9 (build 131 and later).

错误票据JDK-8160328已经作为JDK-8147542的副本被关闭——这个错误已经用java 9的最新EA构建(构建131和更高版本)修复。

I could confirm, that I no longer get the ClassCastException when switching monitors with xrandr.

我可以确认,在使用xrandr切换监视器时,我不再获得ClassCastException。