Java应用程序崩溃与drawString

时间:2015-11-26 15:31:43

标签: java crash jvm

我的Java应用程序出了问题。有时我的应用程序因未知原因崩溃。

我已经复制了问题,并且被起诉的方法似乎是

g.drawString(s, CELL_WIDTH + c * CELL_WIDTH, y)

但是,非常奇怪的是,没有生成任何JVM崩溃文件(hs_pid.log ...),虽然我使用以下命令行选项,但控制台窗口中都没有报告错误

-verbose:gc -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/root/TEST -XX:ErrorFile=/root/TEST/vmlogs%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/root/TEST -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/root/TEST/gc.log

下面你可以找到一个通过强调来重现问题的小测试用例

Thread.sleep (1)

启动程序,在5-6小时后(更多),问题再现。

我使用Java 1.7.0_80(Java 7系列的最新版本)在Linux PC上运行应用程序,并且我使用最新的Java 6也重现了同样的问题。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class TestDraw {

  private static final int WINDOW_WIDTH = 800;

  private static final int WINDOW_HEIGHT = 480;

  private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-:?$";

  private static Random rnd = new Random();

  private static final Font m_font = new Font("monospaced", Font.PLAIN, 22);

  private static final int NUM_ROWS = 17;

  private static final int CELL_WIDTH = 12;

  private static final int ROW_HEIGTH = 25;

  private static final int ROW_WIDTH = WINDOW_WIDTH;

  private static String randomString(int len) {
    StringBuilder sb = new StringBuilder(len);
    for (int i = 0; i < len; i++) {
      sb.append(AB.charAt(rnd.nextInt(AB.length())));
    }
    return sb.toString();
  }

  public static void main(String[] args) {

    JLabel textLabel = new JLabel() {
      @Override
      protected void paintComponent(Graphics g) {

        for (int i = 0; i <= NUM_ROWS; i++) {
          int y_text = (i + 1) * ROW_HEIGTH - 7;
          String text = randomString(64);
          drawString(text, y_text, g, Color.black);
        }
      }

      private void drawString(String text, int y, Graphics g, Color color) {
        for (int c = 0; c < text.length(); c++) {
          String s = text.substring(c, c + 1);
          g.drawString(s, CELL_WIDTH + c * CELL_WIDTH, y);
        }
      }
    };

    JFrame myFrame = new JFrame("TEST COMPONENT");
    myFrame.setLayout(new BorderLayout());
    myFrame.setResizable(false);

    myFrame.add(textLabel, BorderLayout.CENTER);
    myFrame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    myFrame.setVisible(true);
    myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    textLabel.setFont(m_font);

    while (true) {
      textLabel.repaint();
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

我用@Hovercraft Full Of Eels建议更改了测试用例。

这是修改:

textLabel.setFont(m_font);
    Thread t = new Thread(new Runnable() {

      @Override
      public void run() {
        while (true) {
          textLabel.repaint();
          try {
            Thread.sleep(1);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    });
    t.start();
  }

我更新了我的测试用例,添加了@apangin的建议,我在main中调用了这个方法。

  private static void attachShutDownHook() {
    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        System.out.println("Inside Shutdown Hook");
      }
    });
    System.out.println("Shut Down Hook Attached.");
  }

结果是应用程序始终崩溃,但

   System.out.println("Inside Shutdown Hook");

未被调用。

相反,如果我手动杀死Java进程,则会调用先前的打印。

我根据@Hovercraft Full Of Eels的建议修改了我的测试用例。现在我没有使用true和thread.sleep但是使用swing定时器来排队事件线程上的Swing代码。测试用例总是崩溃。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

public class TestDraw {
  private static final int WINDOW_WIDTH = 800;

  private static final int WINDOW_HEIGHT = 480;

  private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-:?$";

  private static Random rnd = new Random();

  private static final Font m_font = new Font("monospaced", Font.PLAIN, 22);

  private static final int NUM_ROWS = 17;

  private static final int CELL_WIDTH = 12;

  private static final int ROW_HEIGTH = 25;

  private static final int ROW_WIDTH = WINDOW_WIDTH;

  private static Timer updateTimer = null;

  private static JLabel textLabel = null;

  private static String randomString(int len) {
    StringBuilder sb = new StringBuilder(len);
    for (int i = 0; i < len; i++) {
      sb.append(AB.charAt(rnd.nextInt(AB.length())));
    }
    return sb.toString();
  }

  public static void main(String[] args) {

    textLabel = new JLabel() {
      @Override
      protected void paintComponent(Graphics g) {

        for (int i = 0; i <= NUM_ROWS; i++) {
          int y_text = (i + 1) * ROW_HEIGTH - 7;
          String text = randomString(64);
          drawString(text, y_text, g, Color.black);
        }
      }

      private void drawString(String text, int y, Graphics g, Color color) {
        for (int c = 0; c < text.length(); c++) {
          String s = text.substring(c, c + 1);
          g.drawString(s, CELL_WIDTH + c * CELL_WIDTH, y);
        }
      }
    };

    updateTimer = new Timer(1, new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        textLabel.repaint();
      }
    });

    JFrame myFrame = new JFrame("TEST COMPONENT");
    myFrame.setLayout(new BorderLayout());
    myFrame.setResizable(false);

    myFrame.add(textLabel, BorderLayout.CENTER);
    myFrame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    myFrame.setVisible(true);
    myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    textLabel.setFont(m_font);
    updateTimer.start();

  }

}

0 个答案:

没有答案