- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
那么,我有一个概念性的问题。我一直在 Android 上使用 JNI 来做低级音频“东西”。我已经用 C/C++ 完成了大量的音频编码,所以我认为这不是什么大问题。我决定在我的“ native ”代码中使用 C++(因为谁不喜欢 OOP?)。我遇到的问题(对我来说)似乎是一个奇怪的问题:当我在 C++ 代码中创建一个用于处理音频的对象时,我从未将这个对象传递给 Java(也没有相反),调用这个对象的方法对象似乎经常调用垃圾收集。由于这是在音频回调中发生的,结果是音频断断续续,而且我经常收到如下消息:
WAIT_FOR_CONCURRENT_GC blocked 23ms
但是,当我通过创建静态函数(而不是调用 memeber 对象的成员方法)执行相同的操作时,应用程序的性能似乎很好,我不再看到上面的日志消息。
基本上,有什么理由调用静态函数应该比在 native 代码中调用成员对象的成员方法有更好的性能?更具体地说,是成员对象,还是完全存在的有限范围变量在涉及垃圾收集的 JNI 项目的 native 代码中? C++调用栈是否参与GC?关于 JNI 编程时 C++ 内存管理如何满足 Java 内存管理,有没有人能给我一些见解?也就是说,如果我不在 Java 和 C++ 之间传递数据,我编写 C++ 代码的方式是否会影响 Java 内存管理(GC 或其他方式)?
请允许我尝试举个例子。请耐心等待,因为它太长了,如果您认为自己有洞察力,欢迎您停止阅读这里。
我有几个对象。负责创建音频引擎、初始化输出等的一个。它称为 HelloAudioJNI(抱歉没有放可编译的示例,但代码很多)。
class CHelloAudioJNI {
... omitted members ...
//member object pointers
COscillator *osc;
CWaveShaper *waveShaper;
... etc ...
public:
//some methods
void init(float fs, int bufferSize, int channels);
... blah blah blah ...
因此,我还有几个类(class)。 WaveShaper 类如下所示:
class CWaveShaper : public CAudioFilter {
protected:
double *coeffs;
unsigned int order;//order
public:
CWaveShaper(const double sampleRate, const unsigned int numChannels,
double *coefficients, const unsigned int order);
double processSample(double input, unsigned int channel);
void reset();
};
我们暂时不用担心 CAudioFilter 类,因为这个例子已经很长了。 WaveShaper .cpp 文件如下所示:
CWaveShaper::CWaveShaper(const double sampleRate,
const unsigned int numChannels,
double *coefficients,
const unsigned int numCoeffs) :
CAudioFilter(sampleRate,numChannels), coeffs(coefficients), order(numCoeffs)
{}
double CWaveShaper::processSample(double input, unsigned int channel)
{
double output = 0;
double pow = input;
//zeroth order polynomial:
output = pow * coeffs[0];
//each additional iteration
for(int iteration = 1; iteration < order; iteration++){
pow *= input;
output += pow * coeffs[iteration];
}
return output;
}
void CWaveShaper::reset() {}
然后是 HelloAudioJNI.cpp。这就是我们进入问题核心的地方。我在 init 函数中使用 new 正确地创建了成员对象,因此:
void CHelloAudioJNI::init(float samplerate, int bufferSize, int channels)
{
... some omitted initialization code ...
//wave shaper numero uno
double coefficients[2] = {1.0/2.0, 3.0/2.0};
waveShaper = new CWaveShaper(fs,outChannels,coefficients,2);
... some more omitted code ...
}
好的,到目前为止一切似乎都很好。然后在音频回调中,我们在成员对象上调用一些成员方法,如下所示:
void CHelloAudioJNI::processOutputBuffer()
{
//compute audio using COscillator object
for(int index = 0; index < outputBuffer.bufferLen; index++){
for(int channel = 0; channel < outputBuffer.numChannels; channel++){
double sample;
//synthesize
sample = osc->computeSample(channel);
//wave-shape
sample = waveShaper->processSample(sample,channel);
//convert to FXP and save to output buffer
short int outputSample = amplitude * sample * FLOAT_TO_SHORT;
outputBuffer.buffer[interleaveIndex(index,channel)] = outputSample;
}
}
}
这就是产生频繁的音频中断和大量关于垃圾回收的消息的原因。但是,如果我将 CWaveShaper::processSample() 函数复制到回调上方的 HelloAudioJNI.cpp 并直接调用它而不是成员函数:
sample = waveShape(sample, coeff, 2);
然后我从我的 Android 设备中听到美妙动听的音频,并且我没有收到如此频繁的关于垃圾回收的消息。问题又来了,是成员对象,还是完全存在于参与垃圾回收的 JNI 项目的 native 代码中的有限范围变量? C++调用栈是否参与GC?关于 JNI 编程时 C++ 内存管理如何满足 Java 内存管理,有没有人能给我一些见解?也就是说,如果我不在 Java 和 C++ 之间传递数据,我编写 C++ 代码的方式是否会影响 Java 内存管理(GC 或其他方式)?
最佳答案
C++对象和Dalvik的垃圾回收没有关系。 Dalvik 对 native 堆的内容不感兴趣,除了它自己的内部存储。从 Java 源创建的所有对象都位于“托管”堆上,这是垃圾收集发生的地方。
Dalvik GC 不检查 native 堆栈; VM 已知的每个线程都有一个单独的堆栈供解释器使用。
C++ 和托管对象相关的唯一方式是,如果您选择通过以某种方式配对对象来创建关系(例如,从 C++ 构造函数创建新的托管对象,或从 Java 终结器删除 native 对象)。
您可以使用 DDMS/ADT 的“分配跟踪器”功能来查看托管堆上最近创建的对象,以及它们是从哪里分配的。如果您在 GC 困惑期间运行它,您应该能够知道是什么导致了它。
此外,logcat 消息显示进程和线程 ID(来自命令行使用,adb logcat -v threadtime
),您应该检查这些信息以确保消息来自您的应用,还可以查看 GC Activity 发生在哪个线程上。您可以在 DDMS/ADT 的“线程”选项卡中看到线程名称。
关于java - Android JNI native 代码中的 C++ 对象是否调用垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16679944/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!