Bug #1605 | support LONGBLOB ! we get java.lang.OutOfMemoryError when having 60MB blob | ||
---|---|---|---|
Submitted: | 20 Oct 2003 5:38 | Modified: | 11 Nov 2009 2:35 |
Reporter: | Ralf Hauser | Email Updates: | |
Status: | Won't fix | Impact on me: | |
Category: | Connector / J | Severity: | S2 (Serious) |
Version: | 3.1.0 nightly (oct 3) | OS: | Linux (RH 9) |
Assigned to: | Mark Matthews | CPU Architecture: | Any |
[20 Oct 2003 5:38]
Ralf Hauser
[20 Oct 2003 16:22]
Mark Matthews
This is a limitation of the MySQL protocol (it does not send 'chunked streams' for blobs...The client has to read the _entire_ blob into memory. Also, realize that most JVMs only allow a default max heap of 64M, so that if you want to work around that, you need to use the '-Xmx' parameter to size the heap appropriately (-Xmx1024M for example would allow the JVM to allocate up to 1GB of heap space). Future versions of the MySQL protcol are planned to support 'chunking' of blob data.
[15 Jan 2004 11:03]
Daniel Applebaum
I retrieve large BLOBs by using repeatedly retrieving only sections of the BLOB using substring, ie: select substring(document, 1, 10240) from documents where docid='3'; and then select substring(document, 10241, 10240) from documents where docid='3'; etc. My servlet turns around and immediately writes the partial response to the client so even the servlet does not need to allocate very much memory. In practice, I use 10MB partial queries.
[21 Sep 2004 2:26]
Brian Harvey
Daniel, You mentioned how you worked around reading a large blob 10meg at a time with substring; how did you store the large blob in the database? Do you have a code sample of your work around? Thank You! I ran into the attached problem: (sounds like the same issue?) Hor ironic you reported this a year ago to the day. Still no fix? Hope someone can help, this is my first post. Im getting an out of memory error trying to store large blobs in a mysql database. I think I have tracked the issue down to connector j. I have code like this to set the blob field with a java.io.InputStream: InputStream fstream = new FileInputStream("C:\\c.zip"); int a = fstream.available(); m_PreStmt.setBinaryStream(5,fstream,a); When the file size gets over 100meg, or 200 meg; I get an out of memory error. My system has over a gig of memory, and I have the JVM set to 500meg. My understanding of setting a blob to an inputstream is that this should avoid the whole (chunk of data) being loaded into memory at once... that the stream would be read a little at a time. I have tried several versions of connector j 3.0.11, 3.0.1.5.ga, and 3.1.4-beta, all give the same out of memory error. In the source for connector j 3.1.4-beta the error occurs in the method ensureCapacity(int additionalData) The line of code is: byte[] newBytes = new byte[newLength]; It seems that the entire chunk of memory is being allocated? Can anyone offer any help? also this seems to be the same type problem as reported in bug # 1605 http://bugs.mysql.com/bug.php?id=1605 Thank You! final void ensureCapacity(int additionalData) throws SQLException { if ((this.position + additionalData) > getBufLength()) { if ((this.position + additionalData) < this.byteBuffer.length) { // byteBuffer.length is != getBufLength() all of the time // due to re-using of packets (we don't shrink them) // // If we can, don't re-alloc, just set buffer length // to size of current buffer setBufLength(this.byteBuffer.length); } else { // // Otherwise, re-size, and pad so we can avoid // allocing again in the near future // int newLength = (int) (this.byteBuffer.length * 1.25); if (newLength < (this.byteBuffer.length + additionalData)) { newLength = this.byteBuffer.length + (int) (additionalData * 1.25); } if (newLength < this.byteBuffer.length) { newLength = this.byteBuffer.length + additionalData; } ---> byte[] newBytes = new byte[newLength]; System.arraycopy(this.byteBuffer, 0, newBytes, 0, this.byteBuffer.length); this.byteBuffer = newBytes; setBufLength(this.byteBuffer.length); } } } How to repeat: Set a blob field to a large file (200 meg or more) like this InputStream fstream = new FileInputStream("C:\\c.zip"); int a = fstream.available(); m_PreStmt.setBinaryStream(5,fstream,a); Try inserting the row into a table. You will get an out of memory error (I have my JVM set to 500 meg) Suggested fix: This is the mthod causing the out of memory error in connector j I copied this from 3.1.14-beta version, but the same proble exists in 3.0.11 and 3.0.15.ga The specific line of code is: byte[] newBytes = new byte[newLength]; final void ensureCapacity(int additionalData) throws SQLException { if ((this.position + additionalData) > getBufLength()) { if ((this.position + additionalData) < this.byteBuffer.length) { // byteBuffer.length is != getBufLength() all of the time // due to re-using of packets (we don't shrink them) // // If we can, don't re-alloc, just set buffer length // to size of current buffer setBufLength(this.byteBuffer.length); } else { // // Otherwise, re-size, and pad so we can avoid // allocing again in the near future // int newLength = (int) (this.byteBuffer.length * 1.25); if (newLength < (this.byteBuffer.length + additionalData)) { newLength = this.byteBuffer.length + (int) (additionalData * 1.25); } if (newLength < this.byteBuffer.length) { newLength = this.byteBuffer.length + additionalData; } ---> byte[] newBytes = new byte[newLength]; System.arraycopy(this.byteBuffer, 0, newBytes, 0, this.byteBuffer.length); this.byteBuffer = newBytes; setBufLength(this.byteBuffer.length); } } }
[12 Nov 2004 14:34]
Ralf Hauser
One option certainly would be to immediately stream it to the disk like org.apache.commons.fileupload are doing it. If doing so, please do not forget security (see http://issues.apache.org/bugzilla/show_bug.cgi?id=32145 and http://issues.apache.org/bugzilla/show_bug.cgi?id=32144)