Opened 15 years ago
Closed 13 years ago
#1294 closed defect (fixed)
custom output causes memory leak?
Reported by: | ioly | Owned by: | |
---|---|---|---|
Priority: | medium | Milestone: | 2.4 |
Component: | Web API | Version: | 2.0.2 |
Severity: | critical | Keywords: | custom output render memory leak |
Cc: | External ID: |
Description
version 2.0.2, bundled tomcat. When using MgByteReader.Read to render custom output,
found memory leak.
my code:
MySession session = ... MyRenderOption option = ... ... MgSelection selection = new MgSelection(map); MgByteReader byteReader = session.getRenderingService().RenderMap( map, selection, envelope, option.ImageWidth, option.ImageHeight, new MgColor(option.R, option.G, option.B), "PNG" ); byte[] tmp = new byte[1024 * 1024]; while (true) { int len = byteReader.Read(tmp, tmp.length); log(len); if (len <= 0){ break; } ...
It worked and outputed the image correctly as expected, but the memory use
increased very fast and the jvm crashed after several calls.
Change History (5)
comment:1 by , 15 years ago
Keywords: | custom output render memory leak added |
---|
comment:2 by , 15 years ago
comment:3 by , 15 years ago
I've tried 2.1 but the problem still exists.
I use the bundled tomcat and the sample package "Sheboygan".
There are two jsp pages and one core class in my app: open_map.jsp, render.jsp, and class "MapService". "open_map.jsp" create a map guide session(and put everything in a global cache, site connection, map, session, rendering service and resource service), "render.jsp" use the former created session to generate custom output, and class "MapService" wraps the low-level operation.
When tomcat started up, I first visit the "open_map.jsp" to create a session, and then I visit "render.jsp" in the same browser window to get the output image, and then I refresh the page again and again. The output image is fine, but the memory use increases very fast.
open_map.jsp:
<%@page import="GIS.MapGuide.Data.Map"%> <%@page import="GIS.MapGuide.Service.MapSession"%> <%@ page import="GIS.MapGuide.Service.MapService"%> <%@page contentType="text/plain;charset=gbk"%> <% MapService service = new MapService(); Map map = service.open("Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition"); session.setAttribute("map", map); out.println(map.toString()); %>
render.jsp:
<%! double inchToMeter(double inch){ return inch * .0254d; } static double _scale = 50000d; void _log(Object s){ System.out.println(s); } %> <% try { _log("begin: " + System.currentTimeMillis()); if (_scale < 1000){ _scale = 50000; }else{ _scale *= 0.9; } Map map = (Map)session.getAttribute("map"); MapService service = new MapService(); RenderOption option = new RenderOption(); option.SessionId = map.getSessionid(); option.Scale = _scale; option.CenterX = map.getViewCenter().getX(); option.CenterY = map.getViewCenter().getY(); option.ImageWidth = 600; option.ImageHeight = 600; byte[] buffer = service.render(option); _log("size: " + buffer.length); response.setHeader("Content-type", "image/png"); response.getOutputStream().write(buffer, 0, buffer.length); _log("end: " + System.currentTimeMillis()); }catch (Exception e) { e.printStackTrace(); } %> <%@ page import="GIS.MapGuide.Data.Map" %> <%@ page import="GIS.MapGuide.Data.RenderOption" %> <%@ page import="GIS.MapGuide.Service.MapService" %>
MapService.java:
package GIS.MapGuide.Service; import GIS.MapGuide.Data.Map; import GIS.MapGuide.Data.RenderOption; import org.osgeo.mapguide.*; import java.io.ByteArrayOutputStream; import java.io.IOException; public class MapService { private static String _config_file; public static void setConfigFilePath(String path) { _config_file = path; MapGuideJavaApi.MgInitializeWebTier(_config_file); } public Map open(String identifier) throws MgException { //login MgUserInformation user = new MgUserInformation("Administrator", "admin"); MgSite site = new MgSite(); site.Open(user); //create session String sessionId = site.CreateSession(); MgSiteConnection con = new MgSiteConnection(); con.Open(user); //get resource service MgResourceService resource_service = (MgResourceService)con.CreateService(MgServiceType.ResourceService); MgMap mm = new MgMap(con); MgResourceIdentifier id = new MgResourceIdentifier(identifier); _log(id.ToString()); _log(id.GetName()); mm.Create(resource_service, id, id.GetName()); String sid = String.format("Session:%s//%s.%s", sessionId, mm.GetName(), MgResourceType.Map); _log(sid); mm.Save(resource_service, new MgResourceIdentifier(sid)); _log(mm.GetResourceId().ToString()); _log(mm.GetMapDefinition().ToString()); //output MapSession session = new MapSession(); MapSessionManager.put(mm.GetSessionId(), session); session.setMap(mm); session.setRenderingService((MgRenderingService)con.CreateService(MgServiceType.RenderingService)); session.setResourceService(resource_service); session.setSessionId(sessionId); session.setSite(site); session.setSiteConnection(con); session.setUser(user); Map map = new Map(); map.setMap(mm); _log(map); return map; } void _log(Object s){ System.out.println(s); } double _inch_to_meter(double inch){ return inch * .0254d; } public byte[] render(RenderOption option) throws MgException, IOException { MapSession session = MapSessionManager.get(option.SessionId); MgMap map = session.getMap(); String srsWkt = map.GetMapSRS(); MgCoordinateSystemFactory coordinateSystemFactory = new MgCoordinateSystemFactory(); MgCoordinateSystem srs = coordinateSystemFactory.Create(srsWkt); double displayInInches = option.ImageHeight * 1d / map.GetDisplayDpi(); double displayInMeters = _inch_to_meter(displayInInches); double mapHeightInMeters = displayInMeters * option.Scale; double mapHeightInMapUnits = srs.ConvertMetersToCoordinateSystemUnits(mapHeightInMeters); double envelopeOffsetY = mapHeightInMapUnits / 2; double envelopeOffsetX = option.ImageWidth * 1d / option.ImageHeight * envelopeOffsetY; MgEnvelope envelope = new MgEnvelope( option.CenterX - envelopeOffsetX, option.CenterY - envelopeOffsetY, option.CenterX + envelopeOffsetX, option.CenterY + envelopeOffsetY ); byte[] tmp = new byte[1024 * 1024]; MgSelection selection = new MgSelection(map); MgByteReader byteReader = session.getRenderingService().RenderMap( map, selection, envelope, option.ImageWidth, option.ImageHeight, new MgColor(option.R, option.G, option.B), "PNG" ); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); while (true) { int len = byteReader.Read(tmp, tmp.length); log(len); if (len <= 0){ break; } if (len > 0) { buffer.write(tmp, 0, len); } else { break; } } byteReader.delete(); tmp = buffer.toByteArray(); buffer.close(); return tmp; } void log(Object s){ System.out.println("MapService: " + s); } }
comment:4 by , 15 years ago
I've found a way to avoid this problem. I notice the "MgByteReader.ToFile" method and I use it to avoid calling "MgByteReader.Read",then it seems working stably.
original code:
byte[] tmp = new byte[1024 * 1024]; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); while (true) { int len = byteReader.Read(tmp, tmp.length); log(len); if (len > 0) { buffer.write(tmp, 0, len); } else { break; } }
new code:
File file = File.createTempFile(session.getSessionId(), ".png"); byteReader.ToFile(file.getAbsolutePath()); FileChannel channel = new FileInputStream(file).getChannel(); ByteBuffer buf = ByteBuffer.allocate((int)channel.size()); while(buf.position() < buf.capacity()){ channel.read(buf); } channel.close(); tmp = buf.array(); file.delete(); buf.clear();
It's not graceful, but works.
comment:5 by , 13 years ago
Milestone: | → 2.4 |
---|---|
Resolution: | → fixed |
Status: | new → closed |
Does the same problem also occur in 2.1?
Please add a sample script and package that can be used to easily reproduce this problem.