gpt4 book ai didi

java - 防止可能由于线程引起的堆内存不足异常

转载 作者:行者123 更新时间:2023-11-30 08:01:58 26 4
gpt4 key购买 nike

目前我正在处理我的第一次内存泄漏,但我似乎无法修复它。我的程序应该通过名为 JukeBox 的类播放 .wav 音频文件。 JukeBox 工作正常,但每次我播放新声音时,java 在任务管理器中使用的内存量都会增加,一旦我点击 ~316,500K 我会收到以下错误System.err 终端:

Exception in thread "Thread-6" java.lang.OutOfMemoryError: Java heap space
at com.sun.media.sound.DirectAudioDevice$DirectClip.open(DirectAudioDevice.java:1135)
at JukeBox.play(JukeBox.java:53)
at Instrument.play(Instrument.java:65)
at Conductor.play(Conductor.java:78)
at Game$2.run(Game.java:42)

在我的调试器中,线程 6 是不断寻找键盘输入(特别是触发声音的线程)的两个线程之一。

这是错误后我的调试器的屏幕截图:image from debugger of threads

所以我相当确定我的问题是由于有太多打开的剪辑线程引起的,但这正是我真正困惑的地方,因为我以为我正在关闭它们,而实际上它们看起来只是卡在那里,等待。

这是我认为我要关闭剪辑的代码:

public void play(int pitch){
jukez = new JukeBox("pianoNote.wav");

Thread clipkill = new Thread() {
public void run() {
try {
Thread.sleep(jukez.getMicrosecondLength()*1000);
} catch (Exception e){System.out.println(e);}
jukez.killTheTunes();
}
};
jukez.play();
clipkill.start();
}

点唱机在这里:

public class JukeBox{
private AudioInputStream stream;
private AudioFormat format;
private DataLine.Info info;
private Clip clip;
private String name;

/**
* Constructor for objects of the class Jukebox
* @param str the filename of the wave file to pla
*/
public JukeBox(String str){
try{
stream = AudioSystem.getAudioInputStream(new File(str));
name = str;
format = stream.getFormat();
info = new DataLine.Info(Clip.class, format);
clip = (Clip) AudioSystem.getLine(info);
} catch(Exception E){
System.out.println(E);
}
}

/**
* Returns the clip's length in microseconds.
* @return the clip's length in microseconds.
*/
public long getMicrosecondLength(){return clip.getMicrosecondLength();}

/**
* Plays the music on its own thread, enabling the game to run while music plays
*/
public void play(){
try {
clip.open(stream);
clip.start();
}
catch (Exception e) {
System.out.println(e);
}
}

/**
* Ends the music and it's thread as well
*/
public void killTheTunes(){
try{stream.close();}catch (Exception e) {
System.out.println(e);
}
clip.close();
}

/**
* Returns the filename the jukebox was initially set to play
* @return the filename the jukebox was initially set to play
*/
public String toString(){
return name;
}
}

我不确定为什么我仍然遇到堆内存问题。谢谢

编辑:

我的代码结构有点复杂,所以我会尽量解释一下。运行游戏的主要方法如下所示:

    display = new Display();
copper = new Conductor();
display.main(); //sets up all the jframe things and graphics
Thread p1 = new Thread() {
public void run() {
while(true){
if(display.panel.playerClicked(1)){
display.panel.p1 = Color.black;
display.panel.p1 = copper.play(4,copper.determinePitch(display.panel.getY(1)));
display.panel.pause(250);
display.panel.p1 = Color.black;
}
}
}
};

Thread p2 = new Thread() {
public void run() {
while(true){
if(display.panel.playerClicked(2)){
display.panel.p2 = Color.black;
display.panel.p2 = copper.play(0,copper.determinePitch(display.panel.getY(2)));
display.panel.pause(250);
display.panel.p2 = Color.black;
}
}
}
};

p1.start();
p2.start();

这是检测按键移动的 Canvas 类。 Display 基本上只是初始化一个 JFrame 并向其添加一个 Canvas。

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.util.ArrayList;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.Image;
import javax.swing.JLabel;
import javax.swing.ImageIcon;


public class Canvas extends JPanel {
// attributes
private Rectangle player1;
private Rectangle player2;

public final int x = 800 + 200;
public final int y = 1100/2 + 200;

private boolean[] player1bools = new boolean[5];
private boolean[] player2bools = new boolean[5];
BufferedImage dimg;

Color p1 = Color.black; //these are intentionally public so game can change them
Color p2 = Color.black;

// constructor
public Canvas() {
// initialize object
player1 = new Rectangle(250, 50, 50, 50);
player2 = new Rectangle(50, 50, 50, 50);

// set canavs background colour

// add the key listener in the constructor of your canavas/panel
addKeyListener(new myKeyListener());


BufferedImage img = null;
try {
img = ImageIO.read(new File("Pencils.jpg"));
} catch (IOException e) {}
dimg = resize(img, x, y-20);

// ensure focus is on this canavas/panel for key operations.
setFocusable(true);
setBackground(new Color(0,0,0,0));
setOpaque(true);

Thread gameLoop = new Thread() {
public void run() {
while(true){
updatePlayers();
repaint();

pause(20);
}

}
};

gameLoop.start();

}

public int getY(int i){
if(i == 1){return player1.y;}
if(i == 2){return player2.y;}
return -1;
}

public boolean isOptimizedDrawingEnabled(){return false;}

/**
* This method was made by David Kroukamp on
* http://stackoverflow.com/questions/14548808/scale-the-imageicon-automatically-to-label-size
*/
public static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
return bi;
}

private void updatePlayers() {
if (player1bools[0]) {
moveX(-5, player1);
}
if (player1bools[2]) {
moveX(5, player1);
}
if (player1bools[1]) {
moveY(-5, player1);
}
if (player1bools[3]) {
moveY(5, player1);
}

if (player2bools[0]) {
moveX(-5, player2);
}
if (player2bools[2]) {
moveX(5, player2);
}
if (player2bools[1]) {
moveY(-5, player2);
}
if (player2bools[3]) {
moveY(5, player2);
}
}

// painting
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics.clearRect(0, 0, getWidth(), getHeight()); //clears the trails

graphics.drawImage(dimg,0,0,null);
Graphics2D graphics2d = (Graphics2D) graphics;
graphics.setColor(p1);
graphics2d.fill(player1);
graphics.setColor(p2);
graphics2d.fill(player2);
// */
}

// function which essentially re-creates rectangle with varying x
// orientations. (x-movement)
public void moveX(int mutationDistance, Rectangle sampleObject) {
//I don't want horizontal movement to work

/*
sampleObject.setBounds(sampleObject.x + mutationDistance,
sampleObject.y, sampleObject.width, sampleObject.height);
*/

}

// function which essentially re-creates rectangle with varying y
// orientations. (y-movement)
public void moveY(int mutationDistance, Rectangle sampleObject) {
if(sampleObject.y < 0) {
sampleObject.y = 0;
}
else if(sampleObject.y > 670) {
sampleObject.y = 670;
}

sampleObject.setBounds(sampleObject.x, sampleObject.y
+ mutationDistance, sampleObject.width, sampleObject.height);
}

public boolean playerClicked(int i){
if(i == 1){return player1bools[4];}
if(i == 2){return player2bools[4];}
return false;
}

// listener
private class myKeyListener implements KeyListener {
// implement all the possible actions on keys
public void keyPressed(final KeyEvent keyEvent) {
if (keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE) {
System.exit(0);
}

if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
player1bools[2] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
player1bools[0] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_UP) {
player1bools[1] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_DOWN) {
player1bools[3] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_SLASH) {
player1bools[4] = true;
}

if (keyEvent.getKeyCode() == KeyEvent.VK_D) {
player2bools[2] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_A) {
player2bools[0] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_W) {
player2bools[1] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_S) {
player2bools[3] = true;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_F) {
player2bools[4] = true;
}

}

public void keyReleased(KeyEvent keyEvent) {
if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
player1bools[2] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
player1bools[0] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_UP) {
player1bools[1] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_DOWN) {
player1bools[3] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_SLASH) {
player1bools[4] = false;
}

if (keyEvent.getKeyCode() == KeyEvent.VK_D) {
player2bools[2] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_A) {
player2bools[0] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_W) {
player2bools[1] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_S) {
player2bools[3] = false;
}
if (keyEvent.getKeyCode() == KeyEvent.VK_F) {
player2bools[4] = false;
}
}

public void keyTyped(KeyEvent keyEvent) {
}
}

public static void pause(int secs) {
try {
Thread.sleep(secs);
} catch (Exception e) {}
}
}

最后是 Conductor,它管理这里的乐器:

public class Conductor
{
private ArrayList<Instrument> symphony;

/**
* Constructor for objects of class Conductor, initializes the instruments
*/
public Conductor()
{
ArrayList<String> pianoList = new ArrayList<String>();
for(int i = 1; i <= 11; i++){
pianoList.add("piano"+i);
}

ArrayList<String> bassList = new ArrayList<String>();
for(int i = 1; i <= 11; i++){
bassList.add("bass"+i);
}

ArrayList<String> guitarList = new ArrayList<String>();
for(int i = 1; i <= 11; i++){
guitarList.add("guitar"+i);
}

ArrayList<String> percList = new ArrayList<String>();
for(int i = 1; i <= 11; i++){
percList.add("perc"+i);
}

ArrayList<String> vibeList = new ArrayList<String>();
for(int i = 1; i <= 11; i++){
vibeList.add("vibe"+i);
}

Instrument piano = new Instrument(pianoList, new Color(19,130,206));
Instrument bass = new Instrument(bassList, new Color(100,83,38));
Instrument guitar = new Instrument(guitarList, new Color(244,184,16));
Instrument perc = new Instrument(percList, new Color(24,57,165));
Instrument vibe = new Instrument(vibeList, new Color(57,24,135));

symphony = new ArrayList<Instrument>();
symphony.add(piano);
symphony.add(bass);
symphony.add(guitar);
symphony.add(perc);
symphony.add(vibe);
}

public static int determinePitch(int i){
if(i == -1){return i;}
if(i>600){return 1;}
if(i>535){return 2;}
if(i>470){return 3;}
if(i>410){return 4;} //these numbers correspond to the approximate heights of the colors in the background image
if(i>345){return 5;}
if(i>275){return 6;}
if(i>215){return 7;}
if(i>155){return 8;}
if(i>90){return 9;}
if(i>25){return 10;}
return 11;
}

/**
* Calls an instrument and makes it play a noise
* @param inst the instrument index to play
* @param pitch the pitch for the instrument to play
*/
public Color play(int inst, int pitch){
symphony.get(inst).play(pitch);
return symphony.get(inst).getColor();
}
}

所以对于结构的整体运行:

控制玩家的线程会检测他们各自的玩家是否按下了触发键。如果是这样,他们会请指挥演奏乐器。他们还改变了该玩家矩形的颜色。当指挥演奏乐器时,它使用 Instrument 的 play 方法,该方法调用乐器的 JukeBox 方法,该方法使用导致崩溃的剪辑。

最佳答案

Thread.sleep() 以毫秒为参数,所以行:

Thread.sleep(jukez.getMicrosecondLength()*1000);

应该是:

Thread.sleep(jukez.getMicrosecondLength()/1000);

您的代码中可能还存在其他问题,但目前您永远不会调用 killTheTunez(),因为您等待的时间太长了百万倍。

关于java - 防止可能由于线程引起的堆内存不足异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37234143/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com