Max Texture-Size: 2048, aber Out-Of-Memory...

  • 8 Antworten
  • Neuester Beitrag
Diskutiere Max Texture-Size: 2048, aber Out-Of-Memory... im Android App Entwicklung im Bereich Betriebssysteme & Apps.
S

Stardust77

Neues Mitglied
Hallo,

ich entwickele eine App auf dem Samsung Galaxy S4 -- darauf treten erfreulich selten irgendwelche Speicherprobleme auf. Dafür aber umso mehr auf dem Nexus S, auf dem ich auch testen kann.

Folgendes Problem: Wenn ich via "GL_MAX_TEXTURE_SIZE" die maximale Texturgröße ermittele, meldet mir das Nexus S (ganz brav) "2048"... Super.
Aber: Alleine schon beim Anlegen einer Bitmap (Config 565) stürzt es mir mit einer Out-Of-Memory-Exception ab.

Wenn ich das also richtig sehe, kann ich mich nicht auf GL_MAX_TEXTURE_SIZE verlassen und muss mich darauf beschränken, deutlich kleinere Texturen anzulegen (für den Textur-Atlas wären größere Texturen halt besser und der GL-Speicher würde ja vermutlich auch ausreichen --- nur eben der Heap nicht). Sehr ärgerlich.

Gibt's eventuell eine Alternative, um Texturen zu laden? Die eben nicht über Bitmap gehen? Die mich also nicht den Speicher erst auf dem Heap anlegen lassen müssen??

Danke!
Grüße,
Philipp
 
U

Unicate

Erfahrenes Mitglied
Hi,

auf GL_MAX_TEXTURE_SIZE ist eigentlich Verlass.
Mir klingt es eher danach, das du beim Hochladen etwas verkehrt machst. Zeig doch mal deinen Code und die genaue Fehlermeldung.
Eine OutOfMemoryException wird nicht von OpenGL geworfen sondern von deinem "Java-Prozess" (Dem Heap, wie du bereits richtig erkannt hast).
Daher liegt die Vermutung nahe, dass du deine Bitmap in einer Schleife erstellst o.ä.
 
Zuletzt bearbeitet:
S

Stardust77

Neues Mitglied
Hi,

naja: Ich lade ja noch gar nichts hoch... :) Ich habe erst mal probehalber ein Bitmap erstellt. Aber gut: Hier der Code zum erstellen eines leeren Bitmaps der Größe 2048x2048:

Code:
Bitmap textureBitmap = Bitmap.createBitmap(2048, 2048, Config.RGB_565);
das geht schon nicht auf dem Nexus S.
Der Vollständigkeit halber, hier aber mein Code zum Laden von Texturen (sämtlicher 2^n Größen --- das verifiziere ich nicht extra im Code, aber es kommen nur 2^n pixel große Bilder rein...):

Code:
    private final void loadTexture(String fileName, int index) {                
        GLES11.glBindTexture(GLES11.GL_TEXTURE_2D, index);
        GLES11.glTexParameterf(GLES11.GL_TEXTURE_2D, GLES11.GL_TEXTURE_MAG_FILTER, GLES11.GL_LINEAR);
        GLES11.glTexParameterf(GLES11.GL_TEXTURE_2D, GLES11.GL_TEXTURE_MIN_FILTER, GLES11.GL_LINEAR);
        Bitmap bitmap = loadBitmap(fileName, Config.RGB_565);
        GLUtils.texImage2D(GLES11.GL_TEXTURE_2D, 0, bitmap, 0);
    }
und der Code zum Laden von Bitmaps:

Code:
    public Bitmap loadBitmap(String fileName, Config config) {
        Options options = new Options();
        options.inPreferredConfig = config;
        InputStream in = null;
        Bitmap bitmap = null;
        try {
            in = assets.open(fileName);
            bitmap = BitmapFactory.decodeStream(in);
            if (bitmap == null)
                throw new RuntimeException("Couldn't load bitmap from asset '" + fileName + "'");
        } catch (IOException e) {
            throw new RuntimeException("Couldn't load bitmap from asset '" + fileName + "'");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
        return bitmap;
    }
Er stürzt beim allerersten Aufruf dieser Methode ab; zu diesem Zeitpunkt ist noch gar nichts passiert (es sind also keine anderen Objekte im Speicher); er versucht "nur", eine 2048x2048 Pixel große Textur zu laden...

Und noch ein Nachtrag: Die genaue Fehlermeldung habe ich mal angefragt (ein Freund testet auf seinem Handy). Das die OOM nicht von OpenGL (ES) kommt, ist schon klar --- nutzt mir nur nichts, wenn ich den "blöden" Heap-Speicher zuerst brauche, um die Textur zu laden. Kann ich nicht "direkt" in den Texturspeicher lesen??
 
Zuletzt bearbeitet:
U

Unicate

Erfahrenes Mitglied
Nachtrag: Nein, ein direktes Lesen in den Texturspeicher ist meines Wissens nicht möglich.

In welcher Methode stürzt er ab? loadBitmap oder loadTexture?`

Wo verwendest du "Bitmap.createBitmap(2048, 2048, Config.RGB_565);"?

Der Stacktrace wäre auch interessant.

PS: Hochladen der Bitmap auf den Grafikchip passiert mit "texImage2D".
 
Zuletzt bearbeitet:
S

Stardust77

Neues Mitglied
Ok, sorry, dass ich mich so unklar ausgedrückt habe. Hier ein neuer Versuch, das ganze zu verdeutlichen: Vergiss mal den "Textur-Lade"-Code. Soweit kommt das Nexus S gar nicht.
Beim Starten der Anwendung (Aktivität) mache ich folgendes (zu Testzwecken!):

Code:
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int deviceWidth = metrics.widthPixels;
        int deviceHeight = metrics.heightPixels;        
        Log.d("[TEST Project]", "Width/Height of Device: " + deviceWidth + ", " + deviceHeight);        
        GLSurfaceView glView = new GLSurfaceView(this);
        glView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); 
        glView.setRenderer(this);        

==> Hier stürzt er jetzt ab:
        Bitmap bitmap = Bitmap.createBitmap(2048, 2048, Config.RGB_565);
        
        ...
    }
Es geht also wirklich nur um das Bitmap. Egal übrigens, ob ich es mit "createBitmap" erzeuge, oder via BitmapFactory.decodeStream von einer Datei in der Größe 2048x2048. In beiden Fällen passiert die gleiche OOM-Exception.
 
A

amfa

Experte
Du könntest mal mit
ActivityManager | Android Developers
Gucken wie viel MB du überhaupt hast.

Wenn ich mich nicht vertue müsste dein Bitmap ja 8 MB brauchen.
(RGB_565 braucht ja 2 byte pro pixel)

Ich weiß nicht wie groß die maximale Heap Size auf dem nexus S ist.
Ich glaube mal gelesen zu haben das dort maximal 32 MB standardmäßig erlaubt sind.
Oder wie viel MB z.B. die GLSurfaeView schon benötigt.

Vielleicht kannste dir hiermit:
Android: how to check how much memory is remaining? - Stack Overflow
Da vorher mal den Speicher anzeigen lassen auf dem Telefon.
Evtl auch vor jedem Aufruf einer Methode, die evtl viel Speicher braucht
 
U

Unicate

Erfahrenes Mitglied
Die Größe des Speichers ist ausreichend!

2048*2048*2=8388608 entspricht 8.3MB

Das Nexus S hat einen Hauptspeicher von 512 MB.
 
S

Stardust77

Neues Mitglied
Hauptspeicher 512 MB ist zwar korrekt, aber die VM erlaubt maximal 32 MB für den Heap (OpenGL hingegen erlaubt mir wieder mehr).
2048 * 2048 * 2 sind aber eben "nur" 8 MB... (Gut, zugegeben: Ein Viertel des Speichers für die Bitmap zu verbrauchen ist schon heftig, aber ich weiß beim besten Willen nicht, wieso das schiefgeht. Der Remaining Heap ist bei 22 MB _vor_ dem Aufruf).

Hilft aber alles nichts: Ich muss halt kleinere Texturen nehmen...

Danke für die Hilfe!
 
U

Unicate

Erfahrenes Mitglied
Schon klar aber 22 ist immer noch größer als 8.3.

Irgendwas ist da nicht i.o.