একটি একক লিনাক্স প্রক্রিয়ার জন্য মেমরির ব্যবহার সীমিত করুন


151

আমি pdftoppmব্যবহারকারী দ্বারা সরবরাহিত পিডিএফকে 300DPI চিত্রে রূপান্তর করতে চলেছি । ব্যবহারকারী খুব বড় পৃষ্ঠা আকারের একটি পিডিএফ সরবরাহ করে তা বাদ দিয়ে এটি দুর্দান্ত কাজ করে। pdftoppmমেমরিতে সেই আকারের 300DPI চিত্র ধরে রাখতে পর্যাপ্ত মেমরি বরাদ্দ করবে, যা 100 ইঞ্চি বর্গ পৃষ্ঠার জন্য প্রতি পিক্সেল = 3.5 গিগাবাইটে 100 * 300 * 100 * 300 * 4 বাইট। একটি দূষিত ব্যবহারকারী আমাকে কেবল একটি মূর্খ-বৃহত পিডিএফ দিতে এবং সমস্ত ধরণের সমস্যার কারণ হতে পারে।

সুতরাং আমি যা করতে চাই তা হল একটি শিশু প্রক্রিয়া চালানোর জন্য মেমরির ব্যবহারের জন্য একধরনের কঠোর সীমাবদ্ধতা রাখুন - 500MB মেমরির চেয়ে বেশি বরাদ্দ দেওয়ার চেষ্টা করা হলে প্রক্রিয়াটি মরে যেতে হবে। এটা কি সম্ভব?

আমি মনে করি না এর জন্য ওলিমিট ব্যবহার করা যেতে পারে, তবে ওয়ান-প্রসেসের সমতুল্য কি আছে?


হতে পারে docker?
শ্রীধর সারনোবাত

উত্তর:


58

ওলিমিট নিয়ে কিছু সমস্যা আছে। এই বিষয়টিতে একটি দরকারী পঠন এখানে রয়েছে: লিনাক্সে একটি প্রোগ্রামের সময় এবং মেমরির ব্যবহার সীমিত করা , যা সময়সীমা সরঞ্জামের দিকে পরিচালিত করে, যা আপনাকে সময় বা মেমরির খরচ দ্বারা একটি প্রক্রিয়া (এবং এর কাঁটাচামচ) খাঁচা করতে দেয়।

টাইমআউট সরঞ্জামটির জন্য পার্ল 5+ এবং /procফাইল সিস্টেমটি মাউন্ট করা দরকার। এর পরে আপনি সরঞ্জামটি অনুলিপি করতে যেমন /usr/local/bin:

curl https://raw.githubusercontent.com/pshved/timeout/master/timeout | \
  sudo tee /usr/local/bin/timeout && sudo chmod 755 /usr/local/bin/timeout

এর পরে, আপনি আপনার প্রশ্নটির মতো মেমরির খরচ করে আপনার প্রক্রিয়াটি 'খাঁচা' করতে পারেন:

timeout -m 500 pdftoppm Sample.pdf

অন্যথায় আপনি ব্যবহার করতে পারে -t <seconds>এবং -x <hertz>যথাক্রমে সময় বা সিপিইউ সীমাবদ্ধতার দ্বারা প্রক্রিয়া সীমিত করতে।

এই সরঞ্জামটি যেভাবে কাজ করে তা হ'ল যদি প্রসারিত প্রক্রিয়াটি তার নির্ধারিত সীমানাগুলি প্রশ্রয় না দেয় তবে প্রতি সেকেন্ডে একাধিকবার পরীক্ষা করে। এর অর্থ আসলে একটি ছোট উইন্ডো রয়েছে যেখানে টাইম আউট নোটিশগুলি এবং প্রক্রিয়াটি মেরে ফেলার আগে কোনও প্রক্রিয়া সম্ভাব্যভাবে ওভারসস্ক্রাইব করতে পারে।

আরও সঠিক পদ্ধতির ফলে ক্রিগ্রুপগুলি জড়িত হতে পারে তবে এটি সেটআপ করার ক্ষেত্রে আরও বেশি জড়িত, এমনকি আপনি ডকার বা রানসি ব্যবহার করেন, যা কিছু বিষয়গুলির মধ্যে, সিগ্রুপের চারপাশে আরও বেশি ব্যবহারকারী-বান্ধব বিমূর্ততা সরবরাহ করে।


আমার জন্য এখন (আবার?) কাজ করছেন বলে মনে হচ্ছে তবে এখানে গুগল ক্যাশে সংস্করণটি রয়েছে: webcache.googleusercontent.com/…
কেভিজেড

আমরা কী টাস্কসেটের সাথে একসাথে টাইমআউট ব্যবহার করতে পারি (আমাদের মেমরি এবং কোর উভয়ই সীমাবদ্ধ করতে হবে)?
আরশ

7
এটি লক্ষ করা উচিত যে এই উত্তরটি coreutilsএকই নামের লিনাক্স স্ট্যান্ডার্ড ইউটিলিটিটির উল্লেখ করছে না ! সুতরাং, উত্তরটি সম্ভাব্যভাবে বিপজ্জনক যদি আপনার সিস্টেমে অন্য কোথাও থাকে তবে কিছু প্যাকেজে timeoutলিনাক্স স্ট্যান্ডার্ড coreutilsপ্যাকেজ হওয়ার প্রত্যাশা স্ক্রিপ্ট রয়েছে ! এই সরঞ্জামটি ডিবিয়ানর মতো বিতরণের জন্য প্যাকেজ করা সম্পর্কে আমি অসচেতন।
ব্যবহারকারী1404316

-t <seconds>প্রতিবন্ধকতা কি এই বহু সেকেন্ড পরে প্রক্রিয়াটিকে হত্যা করে?
xxx374562

116

এটি সীমাবদ্ধ করার আরেকটি উপায় হ'ল লিনাক্সের নিয়ন্ত্রণ গ্রুপগুলি ব্যবহার করা। আপনি ভার্চুয়াল মেমরি থেকে স্বতন্ত্রভাবে শারীরিক মেমরির বরাদ্দকে কোনও প্রক্রিয়াটির (বা প্রক্রিয়াগুলির গ্রুপ) সীমাবদ্ধ করতে চান তবে এটি বিশেষত কার্যকর useful উদাহরণ স্বরূপ:

cgcreate -g memory:myGroup
echo 500M > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes
echo 5G > /sys/fs/cgroup/memory/myGroup/memory.memsw.limit_in_bytes

নামের একটি কন্ট্রোল গ্রুপ তৈরি করবে myGroup, মাইগ্রুপের অধীনে চলমান 500 এমবি দৈহিক মেমরি এবং 5000 এমবি অব অদলবদলের প্রক্রিয়াগুলির সেটটি ক্যাপ করবে। নিয়ন্ত্রণ গোষ্ঠীর অধীনে একটি প্রক্রিয়া চালাতে:

cgexec -g memory:myGroup pdftoppm

নোট করুন যে একটি আধুনিক উবুন্টু বিতরণে এই উদাহরণটির জন্য cgroup-binপ্যাকেজ ইনস্টল করা এবং এতে /etc/default/grubপরিবর্তন GRUB_CMDLINE_LINUX_DEFAULTকরতে সম্পাদনা প্রয়োজন:

GRUB_CMDLINE_LINUX_DEFAULT="cgroup_enable=memory swapaccount=1"

এবং তারপরে চলছে sudo update-grubএবং নতুন কার্নেল বুট পরামিতিগুলি বুট করতে পুনরায় বুট করা হবে।


3
firejailপ্রোগ্রাম এছাড়াও আপনি মেমরি সীমা সঙ্গে একটি প্রক্রিয়া শুরু (ঠিক মেমরির চেয়ে বেশি সীমিত করতে Cgroups এবং নামব্যবধান ব্যবহার করে) দেওয়া হবে। আমার সিস্টেমে এটির জন্য আমাকে কার্নেল কমান্ড লাইনটি পরিবর্তন করতে হবে না!
নেড 64

1
GRUB_CMDLINE_LINUX_DEFAULTঅধ্যবসায় অবিচল করতে আপনার কি পরিবর্তন দরকার ? আমি এখানে এটি অবিচলিত করার অন্য একটি উপায় খুঁজে পেয়েছি ।
ঝড়


এই উত্তরে নোট করা কার্যকর হবে যে কিছু বিতরণে (যেমন উবুন্টু) সিজিক্রিয়েটের জন্য সুডো প্রয়োজন হয়, এবং পরবর্তী কমান্ডগুলিও যদি ব্যবহারকারীর অনুমতি না দেওয়া হয় তবে। এটি পাঠককে অন্য কোথাও এই তথ্যটি খুঁজে পাওয়া থেকে বাঁচাতে পারে (যেমন, জিজ্ঞাসাবাবু / প্রশ্ন / 345055 )। আমি এই প্রভাবটিতে সম্পাদনা করার পরামর্শ দিয়েছিলাম তবে তা প্রত্যাখ্যান করা হয়েছিল।
স্টিবাবাসিক

77

যদি আপনার প্রক্রিয়াটি এমন বেশি বাচ্চাদের জন্ম দেয় না যা সর্বাধিক স্মৃতি গ্রহণ করে তবে আপনি setrlimitফাংশনটি ব্যবহার করতে পারেন । এর জন্য আরও সাধারণ ব্যবহারকারীর ইন্টারফেস ulimitশেলের কমান্ডটি ব্যবহার করছে :

$ ulimit -Sv 500000     # Set ~500 mb limit
$ pdftoppm ...

এটি কেবল আপনার প্রক্রিয়াটির "ভার্চুয়াল" স্মৃতি সীমাবদ্ধ করবে, বিবেচনায় নেওয়া এবং সীমাবদ্ধ করা - প্রক্রিয়াটিকে অন্য প্রক্রিয়াগুলির সাথে ভাগ করে নেওয়া মেমরিটিকে মেমরি ম্যাপ করা হয়েছে তবে সংরক্ষিত নেই (উদাহরণস্বরূপ, জাভার বৃহত স্তূপ)। তবুও, ভার্চুয়াল মেমরি হ'ল প্রক্রিয়াগুলির সবচেয়ে নিকটতম অনুমান যা প্রকৃতপক্ষে বড় হয়, যা বলা ত্রুটিগুলিকে তুচ্ছ করে তোলে।

যদি আপনার প্রোগ্রামটি বাচ্চাদের উত্সাহ দেয় এবং মেমরির বরাদ্দকারী এগুলি হয় তবে এটি আরও জটিল হয়ে ওঠে এবং আপনার নিয়ন্ত্রণে প্রক্রিয়া চালানোর জন্য আপনার সহায়ক স্ক্রিপ্টগুলি লিখতে হবে। আমি আমার ব্লগে লিখেছিলাম, কেন এবং কীভাবে


2
কেন setrlimitআরও বাচ্চাদের জন্য আরও জটিল? man setrlimitআমাকে বলে যে, "একটি শিশু প্রক্রিয়া কাঁটাচামচ মাধ্যমে তৈরি করা (2) তার বাবা সম্পদ সীমা উত্তরাধিকারী রিসোর্স সীমা (2) execve জুড়ে সংরক্ষণ করা হয়।"
আকিরা

6
কার্নেল সমস্ত শিশু প্রসেসের জন্য ভিএম আকারের যোগফল দেয় না; যদি এটি করে তবে উত্তরটি ভুলভাবেই পাওয়া যাবে। সীমাটি প্রতি-প্রক্রিয়াধীন এবং ভার্চুয়াল ঠিকানার স্থান, মেমরির ব্যবহার নয়। মেমরির ব্যবহার পরিমাপ করা শক্ত।
মার্কআর

1
যদি আমি প্রশ্নটি সঠিকভাবে বুঝতে পারি তবে উপ-প্রসেস (সন্তানের) প্রতি সীমা কি ওপি করুন .. মোটে নয়।
আকির

@ মার্কআর, যাইহোক, ভার্চুয়াল অ্যাড্রেস স্পেস ব্যবহৃত মেমরির জন্য একটি ভাল আনুমানিকতা, বিশেষত যদি আপনি এমন কোনও প্রোগ্রাম পরিচালনা করেন যা ভার্চুয়াল মেশিন দ্বারা নিয়ন্ত্রণ করা হয় না (যেমন, জাভা)। কমপক্ষে আমি এর চেয়ে ভাল আর কোনও মেট্রিক জানি না।

2
শুধু ধন্যবাদ বলতে চেয়েছিলেন - এই ulimitপদ্ধতির সঙ্গে আমাকে সাহায্য firefox'র বাগ 622816 - একটি বড় ইমেজ লোড করা হচ্ছে ফায়ারফক্স "ফ্রিজ" করতে পারেন, অথবা সিস্টেম ক্র্যাশ ; যা ইউএসবি বুটে রয়েছে (র‌্যাম থেকে) ওএসকে হিমায়িত করে, যা পুনরায় আরম্ভ করার প্রয়োজন হয়; কমপক্ষে কমপক্ষে firefoxনিজেই ক্র্যাশ হয়ে ওএসকে জীবিত রেখে ... চিয়ার্স!
sdaau

8

আমি নীচের স্ক্রিপ্টটি ব্যবহার করছি, যা দুর্দান্ত কাজ করে। এটি মাধ্যমে cgroups ব্যবহার করে cgmanager আপডেট: এটি এখন থেকে কমান্ড ব্যবহার করে cgroup-toolsএই স্ক্রিপ্টটির নাম দিন limitmemএবং এটি আপনার AT PATH এ রাখুন এবং আপনি এটির মতো ব্যবহার করতে পারেন limitmem 100M bash। এটি মেমরি এবং অদলবদল উভয়ই সীমাবদ্ধ করবে। স্রেফ স্মৃতি সীমাবদ্ধ করতে লাইনটি সরিয়ে দিন memory.memsw.limit_in_bytes

সম্পাদনা: ডিফল্ট লিনাক্স ইনস্টলেশনগুলিতে এটি কেবল মেমরির ব্যবহার সীমাবদ্ধ করে, অদলবদলের ব্যবহার নয়। সোয়াপ ব্যবহার সীমাবদ্ধ করতে সক্ষম করতে আপনার লিনাক্স সিস্টেমে অদলবদ অ্যাকাউন্টিং সক্ষম করতে হবে। সেট করে / এড করে swapaccount=1এটি করুন /etc/default/grubযাতে দেখে মনে হয় এটির মতো

GRUB_CMDLINE_LINUX="swapaccount=1"

তারপরে দৌড়ে sudo update-grubপুনরায় বুট করুন।

দাবি অস্বীকার: cgroup-toolsভবিষ্যতে যদি ভেঙে যায় তবে আমি অবাক হব না । সঠিক সমাধানটি হ'ল সিগ্রুপ ব্যবস্থাপনার জন্য সিস্টেমেড এপিআই ব্যবহার করা হবে তবে এটিএমের জন্য কোনও কমান্ড লাইন সরঞ্জাম নেই

#!/bin/sh

# This script uses commands from the cgroup-tools package. The cgroup-tools commands access the cgroup filesystem directly which is against the (new-ish) kernel's requirement that cgroups are managed by a single entity (which usually will be systemd). Additionally there is a v2 cgroup api in development which will probably replace the existing api at some point. So expect this script to break in the future. The correct way forward would be to use systemd's apis to create the cgroups, but afaik systemd currently (feb 2018) only exposes dbus apis for which there are no command line tools yet, and I didn't feel like writing those.

# strict mode: error if commands fail or if unset variables are used
set -eu

if [ "$#" -lt 2 ]
then
    echo Usage: `basename $0` "<limit> <command>..."
    echo or: `basename $0` "<memlimit> -s <swaplimit> <command>..."
    exit 1
fi

cgname="limitmem_$$"

# parse command line args and find limits

limit="$1"
swaplimit="$limit"
shift

if [ "$1" = "-s" ]
then
    shift
    swaplimit="$1"
    shift
fi

if [ "$1" = -- ]
then
    shift
fi

if [ "$limit" = "$swaplimit" ]
then
    memsw=0
    echo "limiting memory to $limit (cgroup $cgname) for command $@" >&2
else
    memsw=1
    echo "limiting memory to $limit and total virtual memory to $swaplimit (cgroup $cgname) for command $@" >&2
fi

# create cgroup
sudo cgcreate -g "memory:$cgname"
sudo cgset -r memory.limit_in_bytes="$limit" "$cgname"
bytes_limit=`cgget -g "memory:$cgname" | grep memory.limit_in_bytes | cut -d\  -f2`

# try also limiting swap usage, but this fails if the system has no swap
if sudo cgset -r memory.memsw.limit_in_bytes="$swaplimit" "$cgname"
then
    bytes_swap_limit=`cgget -g "memory:$cgname" | grep memory.memsw.limit_in_bytes | cut -d\  -f2`
else
    echo "failed to limit swap"
    memsw=0
fi

# create a waiting sudo'd process that will delete the cgroup once we're done. This prevents the user needing to enter their password to sudo again after the main command exists, which may take longer than sudo's timeout.
tmpdir=${XDG_RUNTIME_DIR:-$TMPDIR}
tmpdir=${tmpdir:-/tmp}
fifo="$tmpdir/limitmem_$$_cgroup_closer"
mkfifo --mode=u=rw,go= "$fifo"
sudo -b sh -c "head -c1 '$fifo' >/dev/null ; cgdelete -g 'memory:$cgname'"

# spawn subshell to run in the cgroup. If the command fails we still want to remove the cgroup so unset '-e'.
set +e
(
set -e
# move subshell into cgroup
sudo cgclassify -g "memory:$cgname" --sticky `sh -c 'echo $PPID'`  # $$ returns the main shell's pid, not this subshell's.
exec "$@"
)

# grab exit code 
exitcode=$?

set -e

# show memory usage summary

peak_mem=`cgget -g "memory:$cgname" | grep memory.max_usage_in_bytes | cut -d\  -f2`
failcount=`cgget -g "memory:$cgname" | grep memory.failcnt | cut -d\  -f2`
percent=`expr "$peak_mem" / \( "$bytes_limit" / 100 \)`

echo "peak memory used: $peak_mem ($percent%); exceeded limit $failcount times" >&2

if [ "$memsw" = 1 ]
then
    peak_swap=`cgget -g "memory:$cgname" | grep memory.memsw.max_usage_in_bytes | cut -d\  -f2`
    swap_failcount=`cgget -g "memory:$cgname" |grep memory.memsw.failcnt | cut -d\  -f2`
    swap_percent=`expr "$peak_swap" / \( "$bytes_swap_limit" / 100 \)`

    echo "peak virtual memory used: $peak_swap ($swap_percent%); exceeded limit $swap_failcount times" >&2
fi

# remove cgroup by sending a byte through the pipe
echo 1 > "$fifo"
rm "$fifo"

exit $exitcode

1
call to cgmanager_create_sync failed: invalid requestপ্রতিটি প্রক্রিয়া জন্য আমি সঙ্গে চালানোর চেষ্টা limitmem 100M processname। আমি Xubuntu 16.04 এলটিএসে আছি এবং সেই প্যাকেজটি ইনস্টল করা আছে।
অ্যারন ফ্র্যাঙ্ক

ওপস, আমি এই ত্রুটি বার্তাটি পেয়েছি: $ limitmem 400M rstudio limiting memory to 400M (cgroup limitmem_24575) for command rstudio Error org.freedesktop.DBus.Error.InvalidArgs: invalid request কোনও ধারণা?
আর কিসলেভ

@ আর কেসিলেভ সিগম্যানার এখন অবচয় করা হয়েছে, এবং উবুন্টু 17.10 তেও পাওয়া যায় না। সিস্টেমড এপিআই এটি ব্যবহার করে যে কোনও সময় পরিবর্তন করা হয়েছিল, সুতরাং সম্ভবত এটি কারণ। আমি স্ক্রিপ্ট আপডেট করেছি সিগ্রুপ-টুলস কমান্ড ব্যবহার করার জন্য।
জানকানিস

যদি percentশূন্যের ফলাফলের জন্য গণনা হয় তবে exprস্থিতি কোডটি 1 হয় এবং এই স্ক্রিপ্টটি অকাল থেকেই বেরিয়ে আসে। লাইনটি এতে পরিবর্তন করার পরামর্শ দিন: percent=$(( "$peak_mem" / $(( "$bytes_limit" / 100 )) ))(রেফ: unix.stackexchange.com/questions/63166/… )
উইল ব্যালেনথিন

আমি যদি সীমা ছাড়িয়ে যাই তবে আমার প্রক্রিয়াটি মেরে ফেলতে আমি কীভাবে সিগ্রুপকে কনফিগার করব?
d9ngle

7

daemontoolsমার্ক জনসন দ্বারা প্রস্তাবিত সরঞ্জামগুলি ছাড়াও , আপনি chpstকোনটি পাওয়া গেছে তাও বিবেচনা করতে পারেন runit। রুনিট নিজেই বান্ডিল হয়ে গেছে busybox, তাই আপনার এটি ইতিমধ্যে ইনস্টল থাকতে পারে।

লোক পৃষ্ঠাchpst বিকল্প দেখায়:

-ম বাইটস সীমাবদ্ধতা স্মৃতি। ডেটা বিভাগ, স্ট্যাক সেগমেন্ট, লকড ফিজিক্যাল পৃষ্ঠাগুলি এবং প্রতিটি প্রক্রিয়াতে মোট বিভাগকে মোট বাইটে সীমাবদ্ধ করুন।


3

আমি উবুন্টু 18.04.2 চালাচ্ছি এবং এলএনএস এবং জানকানিস স্ক্রিপ্ট আমার পরামর্শ মতো কাজ করবে না। চলমান সীমাহীন সোয়াপ limitmem 100M scriptসহ 100 এমবি র‌্যাম সীমাবদ্ধ করছে ।

কোনও প্যারামিটারের নাম নেই বলে limitmem 100M -s 100M scriptদৌড়ে চলা ব্যর্থ cgget -g "memory:$cgname"হয় memory.memsw.limit_in_bytes

সুতরাং আমি অদলবদল অক্ষম করেছি:

# create cgroup
sudo cgcreate -g "memory:$cgname"
sudo cgset -r memory.limit_in_bytes="$limit" "$cgname"
sudo cgset -r memory.swappiness=0 "$cgname"
bytes_limit=`cgget -g "memory:$cgname" | grep memory.limit_in_bytes | cut -d\  -f2`

@ সোর্সজেদি এটি যুক্ত করেছেন :)
d9ngle

2
ঠিক আছে, আমি আমার উত্তর সম্পাদনা করেছি। অদলবদ সীমা সক্ষম করতে আপনার সিস্টেমে অদলবদ অ্যাকাউন্টিং সক্ষম করতে হবে। এতে একটি ছোট রানটাইম ওভারহেড রয়েছে যাতে এটি উবুন্টুতে ডিফল্টরূপে সক্ষম হয় না। আমার সম্পাদনা দেখুন।
জানকানিস

2

যে কোনও সিস্টেমে ভিত্তিক ডিস্ট্রোতে আপনি সিস্টেমড-রানের মাধ্যমেও পরোক্ষভাবে সিগ্রুপগুলি ব্যবহার করতে পারেন। যেমন আপনার pdftoppm500M র্যাম সীমিত করার ক্ষেত্রে , ব্যবহার করুন:

systemd-run --scope -p MemoryLimit=500M pdftoppm

দ্রষ্টব্য: এই আপনাকে পাসওয়ার্ড চাইবে তবে অ্যাপ্লিকেশনটি আপনার ব্যবহারকারী হিসাবে চালু হবে। কমান্ডটির প্রয়োজনের কথা ভেবে এটি আপনাকে বিভ্রান্ত করার অনুমতি দেবেন না sudo, কারণ এর ফলে আদেশটি মূলের নীচে চলে যাবে, যা আপনার উদ্দেশ্য খুব কমই ছিল।

আপনি যদি পাসওয়ার্ডটি প্রবেশ করতে না চান (সর্বোপরি, ব্যবহারকারী হিসাবে আপনি আপনার মেমরির মালিক হন তবে কেন এটি সীমাবদ্ধ করার জন্য আপনার পাসওয়ার্ডের প্রয়োজন হবে) , আপনি --userবিকল্পটি ব্যবহার করতে পারেন , তবে এটি কাজ করার জন্য আপনাকে cgroupsv2 সমর্থন সক্ষম করতে হবে, যা সঠিক কার্নেল প্যারামিটার দিয়েsystemd.unified_cgroup_hierarchy এখন বুট করা দরকার

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.