garbage collection - Android - Heap usage at Application Start and CG_CONCURRENT -
i'm having troubles performances on application because of gc, , don't have experience understand what's going on. here's detailed situation of what's happening.
i'm trying build application processes audio in real time applying stft (quick explanation).
basically, take each buffer (in case, min buffer size 1148 bytes), apply windowing function , obtain matrix of frames; on each frame apply fft; finally, can apply each frame gain based on frequency , on moment in time. path in order obtain modified version of buffer.
since sampling frequency 8000hz, have each buffer processing in less 1148/8000 = 144ms. using system.currenttimemillis()
evaluated each buffer processing takes between 70 , 100 ms, that's fine.
but problem comes garbage collector: memory seems full, can see screenshot below; , gc action makes audio crack sometimes.
the problem i've noticed 2 things:
if don't fft , ifft, leave frame is, cg_concurrent message doesn't display. that's because fft produces lot of data (arrays of complex numbers)
all operations done in separate thread; i've tried cause manually cg ddms perspective after application has been launched. can see code below, in oncreate method application loads layout.. when cause cg, see heap more 90% used ! i've looked @ heap dump , generated leaks suspect report, , of memory occupied class 'android.content.res.resources' , 'android.graphics.bitmap'.. (here's screenshots)
so, have suggestions ? think that's strange memory 90% used @ beginning.. , heap can not increase bit in order satisfy needs
code
mainactivity.java
package com.example.fileoutjava; import java.io.datainputstream; import java.io.ioexception; import java.io.inputstream; import android.app.activity; import android.media.audioformat; import android.media.audiomanager; import android.media.audiotrack; import android.os.bundle; import android.util.log; import android.view.menu; import android.view.view; public class mainactivity extends activity { static final int buffer_factor = 1; datainputstream dis; static final int freq = 8000; static final int frame_lenght = 32; static final int frame_shift = 16; boolean ismusicstopped = true; audiotrack at; thread playthread; long time; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); } public void playmusic(view v) { if (at == null) { log.d("play music", "launching new player"); playthread = new thread(musicplayerthread); playthread.start(); } } public void stopmusic(view v) { ismusicstopped = true; playthread = null; } runnable musicplayerthread = new runnable() { public void run() { thread.currentthread().setpriority(thread.max_priority); /* eg: 8000 bytes per second, 1000 bytes = 125 ms */ inputstream = null; datainputstream dis = null; try { = mainactivity.this.getapplicationcontext().getassets().open("test.wav"); } catch (ioexception e) { e.printstacktrace(); } if (is!=null) dis = new datainputstream(is); //dis = new datainputstream(new bufferedinputstream(is,bsize)); ismusicstopped = false; int min_bsize = audiotrack.getminbuffersize(freq, audioformat.channel_out_mono, audioformat.encoding_pcm_16bit); int bsize = min_bsize*buffer_factor; stft stft = new stft(frame_shift,frame_lenght,freq,bsize); @ = new audiotrack(audiomanager.stream_music, freq, audioformat.channel_out_mono, audioformat.encoding_pcm_16bit, bsize, audiotrack.mode_stream); at.play(); int count = 0; byte[] buffer = new byte[bsize]; time = system.currenttimemillis(); try { while (!ismusicstopped && (count = dis.read(buffer, 0, bsize)) >= 0) { log.d("time elapsed", ""+(system.currenttimemillis()-time)); time = system.currenttimemillis(); //windowing stft.framebuffer(buffer); //fourier transform , inverse stft.fourieranalysis(); // overlapp-add stft.buildbuffer(buffer); at.write(buffer, 0, count); } if (at != null) { at.stop(); at.flush(); at.release(); @ = null; } if (dis != null) { dis.close(); dis = null; } if (is != null) { is.close(); = null; } if (stft != null) stft = null; } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } }; private void stop() { ismusicstopped = true; playthread = null; } @override public boolean oncreateoptionsmenu(menu menu) { // inflate menu; adds items action bar if present. getmenuinflater().inflate(r.menu.main, menu); return true; } @override protected void onpause() { this.stop(); super.onpause(); } @override protected void ondestroy() { this.stop(); super.ondestroy(); } }
stft.java
package com.example.fileoutjava; import java.nio.bytebuffer; import java.nio.byteorder; import android.util.log; import com.badlogic.gdx.audio.analysis.fft; public class stft { private int fs, fl; //frame shift , frame length in ms private int n_fs, n_fl; //frame shift , length in samples private int buf_len; //length of buffer array (bytes) private int data_len; //length of buffer array (converted short) private int padded_data_len; //put 0 padding before , after buffer short[] data private float n_segs; //number of frames can taken 1 buffer array private float[][] stft_matrix; private float[] window; //hamming coefficient private float norm_factor = 0; private boolean search_norm_factor = true; private fft fft; private int i,j,k; //index loops private bytebuffer bb; private float[] tmp_buf; private float[] tmp_fft; private float[] tmp_ifft; public stft(int frame_shift, int frame_length, int freq, int buf_len) { fs = frame_shift; fl = frame_length; this.buf_len = buf_len; this.data_len = buf_len/2; //compute values ms samples n_fs = (int) math.floor(fs*freq/1000); n_fl = (int) math.floor(fl*freq/1000); padded_data_len = 2*n_fl + data_len; //create coefficients window = hamming(n_fl); tmp_buf = new float[padded_data_len]; bb = bytebuffer.allocatedirect(2); bb.order(byteorder.little_endian); //compute how many frames can extracted buffer n_segs = 1 + (float) (math.ceil((this.padded_data_len-n_fl)/n_fs)); //data matrix: size of frame (with padding previous frame) * number of segments stft_matrix = new float[n_fl][(int)n_segs]; log.d("stft stats", "buflen:"+this.buf_len+" // flen:"+n_fl+" // fsh:"+n_fs+ " // nsegs:"+n_segs); //initialize fft object fft = new fft(n_fl*2,freq); //buffers fft data, 0 padding tmp_fft= new float[n_fl*2]; tmp_ifft = new float[n_fl]; (int i=0; i<n_fl*2; i++) { tmp_fft[i] = 0; tmp_ifft[i/2] = 0; } } //frames whole buffer stft matrix public void framebuffer(byte[] buf) { //initialize tmp_buffer , add 0 padding (k=0; k<padded_data_len; k++) tmp_buf[k] = 0; //fill short[] buffer converting byte[] buffer (i=0; i<buf_len; i+=2) { bb.position(0); bb.put(buf[i]); bb.put(buf[i+1]); tmp_buf[n_fl+i/2] = (float) bb.getshort(0); } //frame short[] buffer matrix using windowing (j=0; j<n_segs; j++) { (int i=0; i<n_fl; i++) { stft_matrix[i][j] = tmp_buf[j*n_fs+i]*window[i]; //normalization factor retrieval: first time if (search_norm_factor && (j*n_fs+i) == 512) norm_factor+=window[i]; } } if (search_norm_factor) norm_factor *= 1.2; //retrieve norm factor first time search_norm_factor = false; } //sums frames stft matrix 1 buffer public void buildbuffer(byte[] output) { //initialize tmp_buffer , add 0 padding (k=0; k<padded_data_len; k++) tmp_buf[k] = 0; //overlap-add (j=0; j<n_segs; j++) { (i=0; i<n_fl; i++) { tmp_buf[j*n_fs+i] += stft_matrix[i][j]; } } //convert short[] byte[] (with normalization) (i=0; i<buf_len; i+=2) { bb.position(0); bb.putshort( (short) (tmp_buf[n_fl+i/2]/norm_factor) ); output[i] = bb.get(0); output[i+1] = bb.get(1); } } //fft , ifft of buffer public void fourieranalysis() { (j=0; j<n_segs;j++) { (i=0; i<n_fl; i++) { tmp_fft[i] = stft_matrix[i][j]; } fft.forward(tmp_fft); //operations on spectrum ? fft.inverse(tmp_ifft); (int i=0; i<n_fl; i++) { stft_matrix[i][j] = tmp_ifft[i]; } } } //utility method hamming coefficients private float[] hamming(int len){ float[] win = new float[len]; (i=0; i<len; i++){ win[i] = (float) (0.54-0.46*math.cos((2*math.pi*i)/(len-1))); } return win; } }
the beginning of answer https://stackoverflow.com/a/10679174/987358 explains it: heap increases necessary , @ app start there isn't needed more.
Comments
Post a Comment