mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
ImageViewer: Clamp zoom factor to sane values (#9529)
Should avoid egregious values that would potentially alloc insanely large buffers (and likely fail to do so). In the process, tweak the scale_factor computations when zooming so as to produce slightly less annoying behavior.
This commit is contained in:
@@ -6,6 +6,7 @@ local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local lru = require("ffi/lru")
|
||||
local md5 = require("ffi/sha2").md5
|
||||
local util = require("util")
|
||||
|
||||
local CanvasContext = require("document/canvascontext")
|
||||
if CanvasContext.should_restrict_JIT then
|
||||
@@ -78,95 +79,6 @@ function Cache:_getDiskCache()
|
||||
return cached
|
||||
end
|
||||
|
||||
-- For documentation purposes, here's a battle-tested shell version of calcFreeMem
|
||||
--[[
|
||||
if grep -q 'MemAvailable' /proc/meminfo ; then
|
||||
# We'll settle for 85% of available memory to leave a bit of breathing room
|
||||
tmpfs_size="$(awk '/MemAvailable/ {printf "%d", $2 * 0.85}' /proc/meminfo)"
|
||||
elif grep -q 'Inactive(file)' /proc/meminfo ; then
|
||||
# Basically try to emulate the kernel's computation, c.f., https://unix.stackexchange.com/q/261247
|
||||
# Again, 85% of available memory
|
||||
tmpfs_size="$(awk -v low=$(grep low /proc/zoneinfo | awk '{k+=$2}END{printf "%d", k}') \
|
||||
'{a[$1]=$2}
|
||||
END{
|
||||
printf "%d", (a["MemFree:"]+a["Active(file):"]+a["Inactive(file):"]+a["SReclaimable:"]-(12*low))*0.85;
|
||||
}' /proc/meminfo)"
|
||||
else
|
||||
# Ye olde crap workaround of Free + Buffers + Cache...
|
||||
# Take it with a grain of salt, and settle for 80% of that...
|
||||
tmpfs_size="$(awk \
|
||||
'{a[$1]=$2}
|
||||
END{
|
||||
printf "%d", (a["MemFree:"]+a["Buffers:"]+a["Cached:"])*0.80;
|
||||
}' /proc/meminfo)"
|
||||
fi
|
||||
--]]
|
||||
|
||||
-- And here's our simplified Lua version...
|
||||
function Cache:_calcFreeMem()
|
||||
local memtotal, memfree, memavailable, buffers, cached
|
||||
|
||||
local meminfo = io.open("/proc/meminfo", "r")
|
||||
if meminfo then
|
||||
for line in meminfo:lines() do
|
||||
if not memtotal then
|
||||
memtotal = line:match("^MemTotal:%s-(%d+) kB")
|
||||
if memtotal then
|
||||
-- Next!
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
|
||||
if not memfree then
|
||||
memfree = line:match("^MemFree:%s-(%d+) kB")
|
||||
if memfree then
|
||||
-- Next!
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
|
||||
if not memavailable then
|
||||
memavailable = line:match("^MemAvailable:%s-(%d+) kB")
|
||||
if memavailable then
|
||||
-- Best case scenario, we're done :)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not buffers then
|
||||
buffers = line:match("^Buffers:%s-(%d+) kB")
|
||||
if buffers then
|
||||
-- Next!
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
|
||||
if not cached then
|
||||
cached = line:match("^Cached:%s-(%d+) kB")
|
||||
if cached then
|
||||
-- Ought to be the last entry we care about, we're done
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
meminfo:close()
|
||||
else
|
||||
-- Not on Linux?
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
if memavailable then
|
||||
-- Leave a bit of margin, and report 85% of that...
|
||||
return math.floor(memavailable * 0.85) * 1024, memtotal * 1024
|
||||
else
|
||||
-- Crappy Free + Buffers + Cache version, because the zoneinfo approach is a tad hairy...
|
||||
-- So, leave an even larger margin, and only report 75% of that...
|
||||
return math.floor((memfree + buffers + cached) * 0.75) * 1024, memtotal * 1024
|
||||
end
|
||||
end
|
||||
|
||||
function Cache:insert(key, object)
|
||||
-- If this object is single-handledly too large for the cache, don't cache it.
|
||||
if not self:willAccept(object.size) then
|
||||
@@ -240,10 +152,10 @@ end
|
||||
|
||||
-- Terribly crappy workaround: evict half the cache if we appear to be redlining on free RAM...
|
||||
function Cache:memoryPressureCheck()
|
||||
local memfree, memtotal = self:_calcFreeMem()
|
||||
local memfree, memtotal = util.calcFreeMem()
|
||||
|
||||
-- Nonsensical values? (!Linux), skip this.
|
||||
if memtotal == 0 then
|
||||
if memtotal == nil then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -251,7 +163,9 @@ function Cache:memoryPressureCheck()
|
||||
local free_fraction = memfree / memtotal
|
||||
if free_fraction < 0.20 then
|
||||
logger.warn(string.format("Running low on memory (~%d%%, ~%.2f/%d MiB), evicting half of the cache...",
|
||||
free_fraction * 100, memfree / 1024 / 1024, memtotal / 1024 / 1024))
|
||||
free_fraction * 100,
|
||||
memfree / (1024 * 1024),
|
||||
memtotal / (1024 * 1024)))
|
||||
self.cache:chop()
|
||||
|
||||
-- And finish by forcing a GC sweep now...
|
||||
|
||||
Reference in New Issue
Block a user