您能否在诺基亚手机 (N80/N95) 上使用 Java Midlet 录制音频而不导致 JVM 内存泄漏?

发布于 2024-07-05 05:06:28 字数 2948 浏览 5 评论 0原文

我想使用 Java Midlet 在诺基亚手机上重复捕获音频片段。 我目前的经验是使用Sun文档中的代码(参见:http://java.sun.com/javame/reference/apis/jsr135/javax/microedition/media/control/RecordControl.html) 并将其包装在“while(true) " 循环有效,但应用程序会慢慢消耗手机上的所有内存,并且程序最终会引发异常并且无法启动进一步的录制。

消耗的内存不是 Java 堆内存——我的示例程序(如下)显示 Java 内存大致保持在 185,000 字节左右——但诺基亚提供的底层支持库存在某种内存泄漏; 我相信会发生内存泄漏,因为如果您在运行 Java 应用程序一段时间后尝试启动另一个(非 Java)应用程序(例如 Web 浏览器),手机会杀死该应用程序,并发出有关内存不足的警告。

我已经尝试了几种与Sun文档中的规范示例所采用的方法不同的方法(每次循环时都初始化所有内容,尽可能只初始化一次,调用尽可能多的解除分配风格的函数,这不是绝对必要的) ETC。)。 似乎没有一个成功。 下面是一个简单的示例程序,我认为它应该可以工作,但在 N80(尽管有固件更新)和 N95 上运行 15 分钟左右后崩溃。 其他论坛也报告了此问题,但那里提供的解决方案似乎不起作用(例如,请参阅:http://discussion.forum.nokia.com/forum/showthread.php?t=129876)。

import javax.microedition.media.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;

public class Standalone extends MIDlet {

protected void startApp() {

 final Form form = new Form("Test audio recording");
 final StringItem status = new StringItem("Status","");
 form.append(status);
 final Command exit = new Command("Exit", Command.EXIT, 1);
 form.addCommand(exit);
 form.setCommandListener(new CommandListener() {
    public void commandAction(Command cmd, Displayable disp) {
        if (cmd == exit) {
        destroyApp(false);
        notifyDestroyed();
        }
    }
    });

 Thread t = new Thread(){
    public void run() {
        int counter = 0;
        while(true) {
        //Code cut 'n' paste from Sun JSR135 javadocs for RecordControl:
        try {
            Player p = Manager.createPlayer("capture://audio");
            p.realize();
            RecordControl rc = (RecordControl)p.getControl("RecordControl");
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            rc.setRecordStream(output);
            rc.startRecord();
            p.start();
            Thread.currentThread().sleep(5000);
            rc.commit();
            p.close();
        } catch (Exception e) {
            status.setText("completed "+counter+
                   " T="+Runtime.getRuntime().totalMemory()+
                   " F="+Runtime.getRuntime().freeMemory()+
                   ": Error: "+e);
            break;
        }
        counter++;
        status.setText("completed "+counter+
                   " T="+Runtime.getRuntime().totalMemory()+
                   " F="+Runtime.getRuntime().freeMemory());
        System.gc(); //One forum post suggests this, but doesn't help
        this.yield();
        }
    }
    };
 t.start(); 
 final Display display = Display.getDisplay(this);
 display.setCurrent(form);
}

protected void pauseApp() {}
protected void destroyApp(boolean bool) {}
}    

I would like to repeatedly capture snippets of audio on a Nokia mobile phone with a Java Midlet. My current experience is that using the code in Sun's documentation (see: http://java.sun.com/javame/reference/apis/jsr135/javax/microedition/media/control/RecordControl.html) and wrapping this in a "while(true)" loop works, but the application slowly consumes all the memory on the phone and the program eventually throws an exception and fails to initiate further recordings.

The consumed memory isn't Java heap memory---my example program (below) shows that Java memory stays roughly static at around 185,000 bytes---but there is some kind of memory leak in the underlying supporting library provided by Nokia; I believe the memory leak occurs because if you try and start another (non-Java) application (e.g. web browser) after running the Java application for a while, the phone kills that application with a warning about lack of memory.

I've tried several different approaches from that taken by Sun's canonical example in the documentation (initialize everything each time round the loop, initialize as much as possible only once, call as many of the deallocate-style functions which shouldn't be strictly necessary etc.). None appear to be successful. Below is a simple example program which I believe should work, but crashes after running for 15 minutes or so on both the N80 (despite a firmware update) and N95. Other forums report this problem too, but the solutions presented there do not appear to work (for example, see: http://discussion.forum.nokia.com/forum/showthread.php?t=129876).

import javax.microedition.media.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;

public class Standalone extends MIDlet {

protected void startApp() {

 final Form form = new Form("Test audio recording");
 final StringItem status = new StringItem("Status","");
 form.append(status);
 final Command exit = new Command("Exit", Command.EXIT, 1);
 form.addCommand(exit);
 form.setCommandListener(new CommandListener() {
    public void commandAction(Command cmd, Displayable disp) {
        if (cmd == exit) {
        destroyApp(false);
        notifyDestroyed();
        }
    }
    });

 Thread t = new Thread(){
    public void run() {
        int counter = 0;
        while(true) {
        //Code cut 'n' paste from Sun JSR135 javadocs for RecordControl:
        try {
            Player p = Manager.createPlayer("capture://audio");
            p.realize();
            RecordControl rc = (RecordControl)p.getControl("RecordControl");
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            rc.setRecordStream(output);
            rc.startRecord();
            p.start();
            Thread.currentThread().sleep(5000);
            rc.commit();
            p.close();
        } catch (Exception e) {
            status.setText("completed "+counter+
                   " T="+Runtime.getRuntime().totalMemory()+
                   " F="+Runtime.getRuntime().freeMemory()+
                   ": Error: "+e);
            break;
        }
        counter++;
        status.setText("completed "+counter+
                   " T="+Runtime.getRuntime().totalMemory()+
                   " F="+Runtime.getRuntime().freeMemory());
        System.gc(); //One forum post suggests this, but doesn't help
        this.yield();
        }
    }
    };
 t.start(); 
 final Display display = Display.getDisplay(this);
 display.setCurrent(form);
}

protected void pauseApp() {}
protected void destroyApp(boolean bool) {}
}    

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

唯憾梦倾城 2024-07-12 05:06:28

N 系列诺基亚设备存在已知的内存泄漏。 它不是 Java 特有的,而是位于操作系统底层的某个地方。

最近在开发一款针对诺基亚 N90 的游戏时,我遇到了类似的问题。 我会遇到内存问题,这些问题会在应用程序的多次不同重新启动中累积。 解决方案只是降低游戏中的整体质量和资源量...

我建议尝试更新您的固件,因为新版本应该可以解决这个问题。 然而,诺基亚并没有让升级固件变得非常容易,在大多数情况下,您必须将设备发送给诺基亚。 而且,如果这个应用程序不仅仅供您个人使用,那么您必须预期使用 N 系列设备的任何人都没有最新的固件。

最后,我建议花一些时间浏览一下诺基亚论坛,因为我知道有一些与内存泄漏和 N 系列设备相关的帖子。 这是一篇似乎可以解决您遇到的问题的帖子。

http://discussion.forum.nokia.com/forum/showthread。 php?t=123486

There is a known memory leak with the N-series Nokia devices. It is not specific to Java and is in the underbelly of the OS somewhere.

Recently working on a game that targeted the Nokia N90, I had similar problems. I would run into memory problems that would accumulate over several different restarts of the application. The solution was just to reduce the overall quality and the amount of resources in the game...

I would recommend attempting to update your firmware as newer versions supposedly address this problem. However, Nokia does not make it very easy to upgrade the firmware, in most cases you have to send the device off to Nokia. And, if this app is not just for your own personal use, you have to expect anyone using the N-series devices to not have the latest firmware.

Finally, I would recommend spending some time looking around Forum Nokia as I know there are posts related to memory leaks and the N-series devices. Here is a post that seems to address the problem you are having.

http://discussion.forum.nokia.com/forum/showthread.php?t=123486

潜移默化 2024-07-12 05:06:28

我认为你应该提交错误报告而不是试图解决这个问题。

I think you should file a bugreport instead of trying to work around that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文